001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojava.bio.search; 023 024import java.io.Serializable; 025 026import org.biojava.utils.TriState; 027import org.biojava.utils.walker.WalkerFactory; 028/** 029 * A SearchContentHandler class that implements filtering 030 * in chains of SearchContentHandler instances. 031 * <p> 032 * The SearchContentHandler organise Blast-like searches 033 * as a hierarchy of search/hit/subhit. Each search 034 * is conducted with a single query sequence. Hits 035 * of the query sequence are reported against different 036 * target sequences. The hit is further subdivided into 037 * one of more subhits which represent the positions 038 * within the target sequence that alignments of the query 039 * sequence were achieved against the query sequence 040 * (e.g. HSPs). 041 * <p> 042 * This implementation depends on the a well ordered use 043 * of the SearchContentHandler interface. In particular, 044 * it requires that search/hit/subhit properties are 045 * reported immediately following the associated 046 * startSearch/startHit/startSubHit call. For example, 047 * search properties should not be reported following 048 * the corresponding startHit() call. 049 * <p> 050 * <u>Semantics of this interface</u><br> 051 * BlastLikeSearchFilters test different levels of the 052 * SearchContentHandler property hierarchy and each 053 * filter should be seen as being applied when a full 054 * set of events from that level is received. So the 055 * ByHitProperty filter is applied when endHit() is 056 * called and determines whether all events received 057 * between startHit() and endHit() are to be passed on 058 * or discarded. 059 * <p> 060 * <u>Some keys used by SearchContentHandlers</u><br> 061 * <u>SearchProperties</u><br> 062 * <table border="1"> 063 * <tr> 064 * <td>KEY_QUERY_ID</td> 065 * <td>String. Value from setQueryID</td> 066 * </tr> 067 * <tr> 068 * <td>queryDescription</td> 069 * <td>String. FASTA description line</td> 070 * </tr> 071 * <tr> 072 * <td>program</td> 073 * <td>String. variant of BLAST used</td> 074 * </tr> 075 * <tr> 076 * <td>version</td> 077 * <td>software version</td> 078 * </tr> 079 * </table> 080 * <p> 081 * <u>HitProperties</u><br> 082 * <table border="1" > 083* <tr> 084 * <td>subjectId</td> 085 * <td>String. Identity of subject (target) sequence.</td> 086 * </tr> 087 * <tr> 088 * <td>subjectSequenceLength</td> 089 * <td>String representation of integer value</td> 090 * </tr> 091 * <tr> 092 * <td>subjectDescription</td> 093 * <td>String.</td> 094 * </tr> 095 * <tr> 096 * <td></td> 097 * <td></td> 098 * </tr> 099 * </table> 100 * <p> 101 * <u>SubHitProperties</u><br> 102 * <table border="1" > 103 * <tr> 104 * <td>bitScore</td> 105 * <td>String representation of real value</td> 106 * </tr> 107 * <tr> 108 * <td>queryStrand</td> 109 * <td>plus/minus</td> 110 * </tr> 111 * <tr> 112 * <td>percentageIdentity</td> 113 * <td>String representation of real value</td> 114 * </tr> 115 * <tr> 116 * <td>querySequenceEnd</td> 117 * <td>String representation of integer value</td> 118 * </tr> 119 * <tr> 120 * <td>expectValue</td> 121 * <td>String representation of real value</td> 122 * </tr> 123 * <tr> 124 * <td>subjectStrand</td> 125 * <td>plus/minus</td> 126 * </tr> 127 * <tr> 128 * <td>subjectSequenceEnd</td> 129 * <td>String representation of integer value</td> 130 * </tr> 131 * <tr> 132 * <td>numberOfPositives</td> 133 * <td>String representation of integer value</td> 134 * </tr> 135 * <tr> 136 * <td>score</td> 137 * <td>String representation of integer value</td> 138 * </tr> 139 * <tr> 140 * <td>subjectSequence</td> 141 * <td>String representation of sequence</td> 142 * </tr> 143 * <tr> 144 * <td>alignmentSize</td> 145 * <td>String representation of integer value</td> 146 * </tr> 147 * <tr> 148 * <td>querySequenceStart</td> 149 * <td>String representation of integer value</td> 150 * </tr> 151 * <tr> 152 * <td>subjectSequenceStart</td> 153 * <td>String representation of integer value</td> 154 * </tr> 155 * <tr> 156 * <td>numberOfIdentities</td> 157 * <td>String representation of integer value</td> 158 * </tr> 159 * <tr> 160 * <td>querySequence</td> 161 * <td>String representation of sequence</td> 162 * </tr> 163 * </table> 164 * 165 * 166 * @author David Huen 167 */ 168public interface BlastLikeSearchFilter 169 extends Serializable 170{ 171 public interface Node 172 { 173 public Object getSearchProperty(Object key); 174 public Object getHitProperty(Object key); 175 public Object getSubHitProperty(Object key); 176 } 177 178 public static final String KEY_QUERY_ID = "___QUERY_ID___"; 179 180 /** 181 * returns a TriState indicating the current outcome 182 * of evaluating this filter. This is usually the 183 * outcome saved when evaluate(FilteringContentHandler fch) was called. 184 */ 185 public TriState accept(); 186 187 /** 188 * computes the outcome of this filter on the 189 * specified node and stores it. <b>This method 190 * is only exposed to permit it to be included 191 * in an interface. Users should not use it.</b> 192 */ 193 public void evaluate(Node fch); 194 195 /** 196 * resets the internal state of this filter including 197 * any cached evaluations. <b>This method 198 * is only exposed to permit it to be included 199 * in an interface. Users should not use it.</b> 200 */ 201 public void reset(); 202 203 public abstract static class AbstractBlastLikeSearchFilter 204 implements BlastLikeSearchFilter 205 { 206 protected TriState cachedOutcome = TriState.INDETERMINATE; 207 public TriState accept() { return cachedOutcome; } 208 abstract public void evaluate(Node fch); 209 public void reset() { cachedOutcome = TriState.INDETERMINATE; } 210 211 private AbstractBlastLikeSearchFilter() {} 212 } 213 214 public static final class And 215 { 216 static { WalkerFactory.getInstance().addTypeWithParent(And.class); } 217 218 private AbstractBlastLikeSearchFilter filter0; 219 private AbstractBlastLikeSearchFilter filter1; 220 221 public And( 222 AbstractBlastLikeSearchFilter filter0, 223 AbstractBlastLikeSearchFilter filter1) 224 { 225 this.filter0 = filter0; 226 this.filter1 = filter1; 227 } 228 229 public TriState accept() 230 { 231 TriState outcome0 = filter0.accept(); 232 TriState outcome1 = filter1.accept(); 233 234 if ((outcome0 == TriState.FALSE) || (outcome1 == TriState.FALSE)) 235 return TriState.FALSE; 236 237 // neither can be false now 238 if ((outcome0 == TriState.INDETERMINATE) || (outcome1 == TriState.INDETERMINATE)) 239 return TriState.INDETERMINATE; 240 241 // neither is false nor indeterminate so it must be true! 242 return TriState.TRUE; 243 } 244 } 245 246 public static final class Or 247 { 248 static { WalkerFactory.getInstance().addTypeWithParent(Or.class); } 249 250 private AbstractBlastLikeSearchFilter filter0; 251 private AbstractBlastLikeSearchFilter filter1; 252 253 public Or( 254 AbstractBlastLikeSearchFilter filter0, 255 AbstractBlastLikeSearchFilter filter1) 256 { 257 this.filter0 = filter0; 258 this.filter1 = filter1; 259 } 260 261 public TriState accept() 262 { 263 TriState outcome0 = filter0.accept(); 264 TriState outcome1 = filter1.accept(); 265 266 if ((outcome0 == TriState.TRUE) || (outcome1 == TriState.TRUE)) 267 return TriState.TRUE; 268 269 // neither can be false now 270 if ((outcome0 == TriState.INDETERMINATE) || (outcome1 == TriState.INDETERMINATE)) 271 return TriState.INDETERMINATE; 272 273 // neither is true nor indeterminate so it must be false! 274 return TriState.FALSE; 275 } 276 } 277 278 public static final class Not 279 extends AbstractBlastLikeSearchFilter 280 { 281 static { WalkerFactory.getInstance().addTypeWithParent(Not.class); } 282 283 private AbstractBlastLikeSearchFilter filter; 284 285 public Not(AbstractBlastLikeSearchFilter filter) 286 { 287 this.filter = filter; 288 } 289 290 public TriState accept() 291 { 292 TriState outcome = filter.accept(); 293 294 if (outcome == TriState.INDETERMINATE) 295 return TriState.INDETERMINATE; 296 297 if (outcome == TriState.TRUE) 298 return TriState.FALSE; 299 else 300 return TriState.TRUE; 301 } 302 303 public void evaluate(Node fch) {} 304 } 305 306 /** 307 * Applies test to the value specified by the key in search properties. 308 */ 309 public static final class BySearchProperty 310 extends AbstractBlastLikeSearchFilter 311 { 312 private Object key; 313 private FilterTest test; 314 public BySearchProperty(String key, FilterTest test) 315 { 316 this.key = key; 317 this.test = test; 318 } 319 320 public void evaluate(Node fch) 321 { 322 Object propertyValue = fch.getSearchProperty(key); 323 324 cachedOutcome = ((propertyValue != null) && test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE; 325 } 326 } 327 328 /** 329 * Applies test to the value specified by the key in hit properties. 330 */ 331 public static final class ByHitProperty 332 extends AbstractBlastLikeSearchFilter 333 { 334 private Object key; 335 private FilterTest test; 336 public ByHitProperty(String key, FilterTest test) 337 { 338 this.key = key; 339 this.test = test; 340 } 341 342 public void evaluate(Node fch) 343 { 344 Object propertyValue = fch.getHitProperty(key); 345 346 cachedOutcome = ((propertyValue != null) && test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE; 347 } 348 } 349 350 /** 351 * Applies test to the value specified by the key in subhit properties. 352 */ 353 public static final class BySubHitProperty 354 extends AbstractBlastLikeSearchFilter 355 { 356 private Object key; 357 private FilterTest test; 358 public BySubHitProperty(String key, FilterTest test) 359 { 360 this.key = key; 361 this.test = test; 362 } 363 364 public void evaluate(Node fch) 365 { 366 Object propertyValue = fch.getSubHitProperty(key); 367 //cachedOutcome = ((propertyValue == null) 368 // ? TriState.INDETERMINATE 369 // : (test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE); 370 cachedOutcome = ((propertyValue != null) && test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE; 371 } 372 } 373} 374