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.biojavax.bio.seq; 023 024import java.util.Iterator; 025import java.util.List; 026import java.util.Set; 027import java.util.TreeSet; 028 029import org.biojava.bio.BioException; 030import org.biojava.bio.seq.Feature; 031import org.biojava.bio.seq.FeatureFilter; 032import org.biojava.bio.seq.FeatureHolder; 033import org.biojava.bio.seq.FilterUtils; 034import org.biojava.bio.seq.ProteinTools; 035import org.biojava.bio.seq.SimpleFeatureHolder; 036import org.biojava.bio.symbol.Alphabet; 037import org.biojava.bio.symbol.AlphabetManager; 038import org.biojava.bio.symbol.Edit; 039import org.biojava.bio.symbol.IllegalAlphabetException; 040import org.biojava.bio.symbol.IllegalSymbolException; 041import org.biojava.bio.symbol.Symbol; 042import org.biojava.bio.symbol.SymbolList; 043import org.biojava.ontology.InvalidTermException; 044import org.biojava.utils.ChangeEvent; 045import org.biojava.utils.ChangeSupport; 046import org.biojava.utils.ChangeVetoException; 047import org.biojavax.Namespace; 048import org.biojavax.RichObjectFactory; 049import org.biojavax.bio.SimpleBioEntry; 050 051/** 052 * A simple implementation of RichSequence. It has no sequence data, and 053 * delegates to a RichSequenceHandler to do sequence handling. 054 * 055 * @author Richard Holland 056 * @since 1.5 057 */ 058public class ThinRichSequence extends SimpleBioEntry implements RichSequence { 059 060 private final static String ISCIRCULAR = "X"; 061 062 private Set<Feature> features = new TreeSet<Feature>(); 063 private Double symListVersion; 064 private boolean circular; 065 066 /** 067 * Creates a new instance of ThinRichSequence. Note the use of Double for 068 * seqversion, which indicates that it is nullable. 069 * 070 * @param ns 071 * the namespace for this sequence. 072 * @param name 073 * the name of the sequence. 074 * @param accession 075 * the accession of the sequence. 076 * @param version 077 * the version of the sequence. 078 * @param seqversion 079 * the version of the symbols for the sequence. 080 */ 081 public ThinRichSequence(Namespace ns, String name, String accession, 082 int version, Alphabet alpha, Double seqversion) { 083 super(ns, name, accession, version); 084 this.symListVersion = seqversion; 085 this.circular = false; 086 this.alphabet = alpha; 087 } 088 089 // Hibernate requirement - not for public use. 090 protected ThinRichSequence() { 091 } 092 093 /** 094 * {@inheritDoc} 095 */ 096 public Double getSeqVersion() { 097 return this.symListVersion; 098 } 099 100 /** 101 * {@inheritDoc} 102 */ 103 public void setSeqVersion(Double seqVersion) throws ChangeVetoException { 104 if (!this.hasListeners(RichSequence.SYMLISTVERSION)) { 105 this.symListVersion = seqVersion; 106 } else { 107 ChangeEvent ce = new ChangeEvent(this, RichSequence.SYMLISTVERSION, 108 seqVersion, this.symListVersion); 109 ChangeSupport cs = this 110 .getChangeSupport(RichSequence.SYMLISTVERSION); 111 synchronized (cs) { 112 cs.firePreChangeEvent(ce); 113 this.symListVersion = seqVersion; 114 cs.firePostChangeEvent(ce); 115 } 116 } 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 public void setCircular(boolean circular) throws ChangeVetoException { 123 if (!this.hasListeners(RichSequence.CIRCULAR)) { 124 this.circular = circular; 125 } else { 126 ChangeEvent ce = new ChangeEvent(this, RichSequence.CIRCULAR, 127 new Boolean(circular), new Boolean(this.circular)); 128 ChangeSupport cs = this.getChangeSupport(RichSequence.CIRCULAR); 129 synchronized (cs) { 130 cs.firePreChangeEvent(ce); 131 this.circular = circular; 132 cs.firePostChangeEvent(ce); 133 } 134 } 135 } 136 137 /** 138 * {@inheritDoc} 139 */ 140 public boolean getCircular() { 141 return this.circular; 142 } 143 144 // Hibernate requirement - not for public use. 145 String getCircularChar() { 146 return getCircular() ? ISCIRCULAR : null; 147 } 148 149 // Hibernate requirement - not for public use. 150 void setCircularChar(final String isHiddenChar) throws ChangeVetoException { 151 setCircular(isHiddenChar != null 152 || (isHiddenChar != null && isHiddenChar.length() > 0));// any 153 // character 154 // will 155 // set 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 public void edit(Edit edit) throws IndexOutOfBoundsException, 162 IllegalAlphabetException, ChangeVetoException { 163 RichObjectFactory.getDefaultRichSequenceHandler().edit(this, edit); 164 } 165 166 /** 167 * {@inheritDoc} 168 */ 169 public Symbol symbolAt(int index) throws IndexOutOfBoundsException { 170 return RichObjectFactory.getDefaultRichSequenceHandler().symbolAt(this, 171 index); 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 public List toList() { 178 return RichObjectFactory.getDefaultRichSequenceHandler().toList(this); 179 } 180 181 /** 182 * {@inheritDoc} 183 */ 184 public String subStr(int start, int end) throws IndexOutOfBoundsException { 185 return RichObjectFactory.getDefaultRichSequenceHandler().subStr(this, 186 start, end); 187 } 188 189 /** 190 * {@inheritDoc} 191 */ 192 public SymbolList subList(int start, int end) 193 throws IndexOutOfBoundsException { 194 return RichObjectFactory.getDefaultRichSequenceHandler().subList(this, 195 start, end); 196 } 197 198 /** 199 * {@inheritDoc} 200 */ 201 public String seqString() { 202 return RichObjectFactory.getDefaultRichSequenceHandler() 203 .seqString(this); 204 } 205 206 /** 207 * {@inheritDoc} 208 */ 209 public int length() { 210 return this.length; 211 } 212 213 /** 214 * {@inheritDoc} 215 */ 216 public Iterator iterator() { 217 return RichObjectFactory.getDefaultRichSequenceHandler().iterator(this); 218 } 219 220 /** 221 * {@inheritDoc} 222 */ 223 public Alphabet getAlphabet() { 224 return this.alphabet; 225 } 226 227 // Hibernate requirement - not for public use. 228 private Alphabet alphabet; 229 230 // Hibernate requirement - not for public use. 231 protected void setAlphabetName(String alphaname) 232 throws IllegalSymbolException, BioException { 233 if (alphaname.equals("protein")) 234 alphaname = ProteinTools.getTAlphabet().getName(); 235 this.alphabet = AlphabetManager.alphabetForName(alphaname); 236 } 237 238 // Hibernate requirement - not for public use. 239 protected String getAlphabetName() { 240 if (this.alphabet == null) 241 return null; 242 String name = this.alphabet.getName(); 243 if (name.equals(ProteinTools.getTAlphabet().getName())) 244 return "protein"; 245 else 246 return name; 247 } 248 249 // Hibernate requirement - not for public use. 250 private int length = 0; 251 252 // Hibernate requirement - not for public use. 253 protected void setSequenceLength(int length) { 254 this.length = length; 255 } 256 257 // Hibernate requirement - not for public use. 258 protected int getSequenceLength() { 259 return this.length; 260 } 261 262 /** 263 * {@inheritDoc} 264 */ 265 public String getURN() { 266 return this.getName(); 267 } 268 269 /** 270 * {@inheritDoc} 271 */ 272 public FeatureHolder filter(FeatureFilter fc, boolean recurse) { 273 SimpleFeatureHolder fh = new SimpleFeatureHolder(); 274 for (Iterator<Feature> i = this.features.iterator(); i.hasNext();) { 275 Feature f = (RichFeature) i.next(); 276 try { 277 if (fc.accept(f)) 278 fh.addFeature(f); 279 } catch (ChangeVetoException e) { 280 throw new RuntimeException( 281 "What? You don't like our features??"); 282 } 283 } 284 return fh; 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 public Feature createFeature(Feature.Template ft) throws BioException, 291 ChangeVetoException { 292 Feature f; 293 try { 294 f = new SimpleRichFeature(this, ft); 295 } catch (InvalidTermException e) { 296 throw new ChangeVetoException("They don't like our term", e); 297 } 298 if (!this.hasListeners(RichSequence.FEATURES)) { 299 this.features.add(f); 300 } else { 301 ChangeEvent ce = new ChangeEvent(this, RichSequence.FEATURES, f, 302 null); 303 ChangeSupport cs = this.getChangeSupport(RichSequence.FEATURES); 304 synchronized (cs) { 305 cs.firePreChangeEvent(ce); 306 this.features.add(f); 307 cs.firePostChangeEvent(ce); 308 } 309 } 310 return f; 311 } 312 313 /** 314 * {@inheritDoc} 315 */ 316 public void removeFeature(Feature f) throws ChangeVetoException, 317 BioException { 318 if (!(f instanceof RichFeature)) 319 f = RichFeature.Tools.enrich(f); 320 if (!this.hasListeners(RichSequence.FEATURES)) { 321 this.features.remove(f); 322 } else { 323 ChangeEvent ce = new ChangeEvent(this, RichSequence.FEATURES, null, 324 f); 325 ChangeSupport cs = this.getChangeSupport(RichSequence.FEATURES); 326 synchronized (cs) { 327 cs.firePreChangeEvent(ce); 328 this.features.remove(f); 329 cs.firePostChangeEvent(ce); 330 } 331 } 332 } 333 334 /** 335 * {@inheritDoc} 336 */ 337 public boolean containsFeature(Feature f) { 338 try { 339 if (!(f instanceof RichFeature)) 340 f = RichFeature.Tools.enrich(f); 341 } catch (ChangeVetoException e) { 342 // We just can't tell! 343 return false; 344 } 345 return this.features.contains(f); 346 } 347 348 /** 349 * {@inheritDoc} 350 */ 351 public FeatureHolder filter(FeatureFilter filter) { 352 boolean recurse = !FilterUtils.areProperSubset(filter, 353 FeatureFilter.top_level); 354 return this.filter(filter, recurse); 355 } 356 357 /** 358 * {@inheritDoc} <b>Warning</b> this method gives access to the original 359 * Collection not a copy. This is required by Hibernate. If you modify the 360 * object directly the behaviour may be unpredictable. 361 */ 362 public Set<Feature> getFeatureSet() { 363 return this.features; 364 } // must be original for Hibernate 365 366 /** 367 * {@inheritDoc} <b>Warning</b> this method gives access to the original 368 * Collection not a copy. This is required by Hibernate. If you modify the 369 * object directly the behaviour may be unpredictable. 370 */ 371 public void setFeatureSet(Set<Feature> features) throws ChangeVetoException { 372 this.features = features; 373 } // must be original for Hibernate 374 375 /** 376 * {@inheritDoc} 377 */ 378 public FeatureFilter getSchema() { 379 return FeatureFilter.top_level; 380 } 381 382 /** 383 * {@inheritDoc} <b>Warning</b> this method gives access to the original 384 * Collection not a copy. This is required by Hibernate. If you modify the 385 * object directly the behaviour may be unpredictable. 386 */ 387 public Iterator<Feature> features() { 388 return this.getFeatureSet().iterator(); 389 } 390 391 /** 392 * {@inheritDoc} 393 */ 394 public int countFeatures() { 395 return this.features.size(); 396 } 397 398 /** 399 * {@inheritDoc} 400 */ 401 public SymbolList getInternalSymbolList() { 402 return SymbolList.EMPTY_LIST; 403 } 404}