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 022 023package org.biojava.bio.dist; 024 025import java.io.IOException; 026import java.io.ObjectInputStream; 027import java.io.ObjectOutputStream; 028import java.io.Serializable; 029 030import org.biojava.bio.BioError; 031import org.biojava.bio.symbol.Alphabet; 032import org.biojava.bio.symbol.AlphabetIndex; 033import org.biojava.bio.symbol.AlphabetManager; 034import org.biojava.bio.symbol.AtomicSymbol; 035import org.biojava.bio.symbol.FiniteAlphabet; 036import org.biojava.bio.symbol.IllegalAlphabetException; 037import org.biojava.bio.symbol.IllegalSymbolException; 038import org.biojava.bio.symbol.Symbol; 039import org.biojava.utils.AbstractChangeable; 040import org.biojava.utils.ChangeEvent; 041import org.biojava.utils.ChangeListener; 042import org.biojava.utils.ChangeSupport; 043import org.biojava.utils.ChangeVetoException; 044 045/** 046 * An encapsulation of a count over the Symbols within a FiniteAlphabet using 047 * an AlphabetIndex object. 048 * 049 * @author Matthew Pocock 050 * @author Mark Schreiber (serialization) 051 * @author Thomas Down (more serialization...) 052 * @since 1.1 053 */ 054public final class IndexedCount 055 extends 056 AbstractChangeable 057 implements 058 Count, Serializable 059{ 060 static final long serialVersionUID = -1764931829553447679L; 061 062 //must be transient as indices may vary between VM's 063 private transient AlphabetIndex indexer; 064 private transient double[] counts; 065 private FiniteAlphabet alpha; 066 067 public Alphabet getAlphabet() { 068 return alpha; 069 } 070 071 public double getCount(AtomicSymbol s) throws IllegalSymbolException { 072 return counts[indexer.indexForSymbol(s)]; 073 } 074 075 public void setCount(AtomicSymbol s, double c) 076 throws IllegalSymbolException, ChangeVetoException { 077 if(!hasListeners()) { 078 counts[indexer.indexForSymbol(s)] = c; 079 } else { 080 ChangeSupport changeSupport = getChangeSupport(COUNTS); 081 synchronized(changeSupport) { 082 int index = indexer.indexForSymbol(s); 083 ChangeEvent ce = new ChangeEvent( 084 this, COUNTS, 085 new Object[] { s, new Double(counts[index]) }, 086 new Object[] { s, new Double(c) } 087 ); 088 changeSupport.firePreChangeEvent(ce); 089 counts[index] = c; 090 changeSupport.firePostChangeEvent(ce); 091 } 092 } 093 } 094 095 public void increaseCount(AtomicSymbol s, double c) 096 throws IllegalSymbolException, ChangeVetoException { 097 if(!hasListeners()) { 098 counts[indexer.indexForSymbol(s)] += c; 099 } else { 100 ChangeSupport changeSupport = getChangeSupport(COUNTS); 101 synchronized(changeSupport) { 102 int index = indexer.indexForSymbol(s); 103 double oc = counts[index]; 104 double nc = oc + c; 105 ChangeEvent ce = new ChangeEvent( 106 this, COUNTS, 107 new Object[] { s, new Double(oc) }, 108 new Object[] { s, new Double(nc) } 109 ); 110 changeSupport.firePreChangeEvent(ce); 111 counts[index] = nc; 112 changeSupport.firePostChangeEvent(ce); 113 } 114 } 115 } 116 117 public void setCounts(Count c) 118 throws IllegalAlphabetException, ChangeVetoException { 119 if(c.getAlphabet() != getAlphabet()) { 120 throw new IllegalAlphabetException( 121 "Alphabet must match: " + c.getAlphabet().getName() + 122 " != " + c.getAlphabet().getName() 123 ); 124 } 125 126 try { 127 if(!hasListeners()) { 128 for(int i = 0; i < counts.length; i++) { 129 counts[i] = c.getCount((AtomicSymbol) indexer.symbolForIndex(i)); 130 } 131 } else { 132 ChangeSupport changeSupport = getChangeSupport(COUNTS); 133 synchronized(changeSupport) { 134 ChangeEvent ce = new ChangeEvent( 135 this, COUNTS 136 ); 137 changeSupport.firePreChangeEvent(ce); 138 for(int i = 0; i < counts.length; i++) { 139 counts[i] = c.getCount((AtomicSymbol) indexer.symbolForIndex(i)); 140 } 141 changeSupport.firePostChangeEvent(ce); 142 } 143 } 144 } catch (IllegalSymbolException ise) { 145 throw new BioError( 146 "Assertion Failure: Should have no illegal symbols", ise 147 ); 148 } 149 } 150 151 public void zeroCounts() 152 throws ChangeVetoException { 153 if(!hasListeners()) { 154 for(int i = 0; i < counts.length; i++) { 155 counts[i] = 0.0; 156 } 157 } else { 158 ChangeSupport changeSupport = getChangeSupport(COUNTS); 159 synchronized(changeSupport) { 160 ChangeEvent ce = new ChangeEvent( 161 this, COUNTS 162 ); 163 changeSupport.firePreChangeEvent(ce); 164 for(int i = 0; i < counts.length; i++) { 165 counts[i] = 0.0; 166 } 167 changeSupport.firePostChangeEvent(ce); 168 } 169 } 170 } 171 172 173 174 private static class SymbolWeightMemento implements Serializable { 175 static final long serialVersionUID = 5223128163879670657L; 176 177 public final Symbol symbol; 178 public final double weight; 179 180 public SymbolWeightMemento(Symbol s, double weight) { 181 this.symbol = s; 182 this.weight = weight; 183 } 184 } 185 186 private void writeObject(ObjectOutputStream oos) 187 throws IOException 188 { 189 oos.defaultWriteObject(); 190 191 SymbolWeightMemento[] swm = new SymbolWeightMemento[counts.length]; 192 for (int w = 0; w < swm.length; ++w) { 193 swm[w] = new SymbolWeightMemento(indexer.symbolForIndex(w), counts[w]); 194 } 195 oos.writeObject(swm); 196 } 197 198 private void readObject(ObjectInputStream stream) 199 throws IOException, ClassNotFoundException 200 { 201 stream.defaultReadObject(); 202 indexer = AlphabetManager.getAlphabetIndex(alpha); 203 counts = new double[alpha.size()]; 204 205 SymbolWeightMemento[] swm = (SymbolWeightMemento[]) stream.readObject(); 206 for (int m = 0; m < swm.length; ++m) { 207 try { 208 counts[indexer.indexForSymbol(swm[m].symbol)] = swm[m].weight; 209 } catch (IllegalSymbolException ex) { 210 throw new IOException("Symbol in serialized stream can't be found in the alphabet"); 211 } 212 } 213 } 214 215 /** 216 * Get a new IdexedCount for an alphabet using the default indexer. 217 * 218 * @param fa the FiniteAlphabet to count 219 */ 220 public IndexedCount(FiniteAlphabet fa) { 221 this(AlphabetManager.getAlphabetIndex(fa)); 222 } 223 224 /** 225 * Get a new InexedCount for an alphabet indexer. 226 * 227 * @param indexer the AlphabetIndex used to map between symbols and indecies 228 */ 229 public IndexedCount(AlphabetIndex indexer) { 230 indexer.addChangeListener(ChangeListener.ALWAYS_VETO, AlphabetIndex.INDEX); 231 this.indexer = indexer; 232 this.counts = new double[indexer.getAlphabet().size()]; 233 this.alpha = indexer.getAlphabet(); 234 } 235}