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 */ 021package org.biojava.nbio.core.sequence.template; 022 023import org.biojava.nbio.core.exceptions.TranslationException; 024import org.biojava.nbio.core.sequence.io.template.SequenceCreatorInterface; 025 026import java.util.*; 027 028 029public abstract class AbstractCompoundTranslator<F extends Compound, T extends Compound> 030 implements CompoundTranslator<F, T> { 031 032 private final SequenceCreatorInterface<T> creator; 033 private final Map<F, List<T>> mapper; 034 private final CompoundSet<F> fromCompoundSet; 035 private final CompoundSet<T> toCompoundSet; 036 037 public AbstractCompoundTranslator(SequenceCreatorInterface<T> creator, 038 CompoundSet<F> fromCompoundSet, CompoundSet<T> toCompoundSet) { 039 this.creator = creator; 040 this.mapper = new HashMap<F, List<T>>(); 041 this.fromCompoundSet = fromCompoundSet; 042 this.toCompoundSet = toCompoundSet; 043 } 044 045 public SequenceCreatorInterface<T> getCreator() { 046 return creator; 047 } 048 049 public CompoundSet<F> getFromCompoundSet() { 050 return fromCompoundSet; 051 } 052 053 public CompoundSet<T> getToCompoundSet() { 054 return toCompoundSet; 055 } 056 057 @SuppressWarnings("unchecked") 058 protected void addStrings(String source, String... targets) { 059 F f = getFromCompoundSet().getCompoundForString(source); 060 for (String t : targets) { 061 addCompounds(f, getToCompoundSet().getCompoundForString(t)); 062 } 063 } 064 065 protected void addCompounds(F source, T... targets) { 066 067 List<T> l = mapper.get(source); 068 if ( l == null) { 069 l = new ArrayList<T>(); 070 mapper.put(source, l); 071 } 072 l.addAll(Arrays.asList(targets)); 073 } 074 075 @Override 076 public List<T> translateMany(F fromCompound) { 077 if (!mapper.containsKey(fromCompound)) { 078 throw new TranslationException("Can not translate compound "+fromCompound); 079 } 080 return mapper.get(fromCompound); 081 } 082 083 @Override 084 public T translate(F fromCompound) { 085 List<T> compounds = translateMany(fromCompound); 086 if (compounds.isEmpty()) { 087 throw new TranslationException("No compounds found for " + fromCompound); 088 } 089 else if (compounds.size() > 1) { 090 throw new TranslationException("Too many compounds found for " 091 + fromCompound); 092 } 093 else { 094 return compounds.get(0); 095 } 096 } 097 098 @Override 099 public List<Sequence<T>> createSequences(Sequence<F> originalSequence) { 100 List<List<T>> workingList = new ArrayList<List<T>>(); 101 for (F source : originalSequence) { 102 List<T> compounds = translateMany(source); 103 104 // Translate source to a list of possible compounds; if we have 1 then 105 // just add onto the list. If we have n then start new paths in all 106 // sequences i.e. 107 // 108 // MTAS (A & S have 2 routes) makes 109 // AUG UGG GAU AGU 110 // AUG UGG GAC AGU 111 // AUG UGG GAU AGC 112 // AUG UGG GAC AGC 113 if (compounds.isEmpty()) { 114 throw new TranslationException("Compound " + source + " resulted in " 115 + "no target compounds"); 116 } 117 addCompoundsToList(compounds, workingList); 118 } 119 120 postProcessCompoundLists(workingList); 121 122 return workingListToSequences(workingList); 123 } 124 125 protected abstract void postProcessCompoundLists(List<List<T>> compoundLists); 126 127 protected void addCompoundsToList(List<T> compounds, List<List<T>> workingList) { 128 int size = compounds.size(); 129 List<List<T>> currentWorkingList = new ArrayList<List<T>>(); 130 for (int i = 0; i < size; i++) { 131 boolean last = (i == (size - 1)); 132 // If last run we add the compound to the top set of lists & then 133 // add the remaining ones in 134 if (last) { 135 addCompoundToLists(workingList, compounds.get(i)); 136 if (!currentWorkingList.isEmpty()) { 137 workingList.addAll(currentWorkingList); 138 } 139 } 140 // Otherwise duplicate the current sequence set and add this compound 141 else { 142 List<List<T>> duplicate = duplicateList(workingList); 143 addCompoundToLists(duplicate, compounds.get(i)); 144 currentWorkingList.addAll(duplicate); 145 } 146 } 147 } 148 149 protected List<Sequence<T>> workingListToSequences(List<List<T>> workingList) { 150 List<Sequence<T>> sequences = new ArrayList<Sequence<T>>(); 151 for (List<T> seqList : workingList) { 152 sequences.add(getCreator().getSequence(seqList)); 153 } 154 return sequences; 155 } 156 157 private List<List<T>> duplicateList(List<List<T>> incoming) { 158 List<List<T>> outgoing = new ArrayList<List<T>>(); 159 for (List<T> current : incoming) { 160 outgoing.add(new ArrayList<T>(current)); 161 } 162 return outgoing; 163 } 164 165 protected void addCompoundToLists(List<List<T>> list, T compound) { 166 167 if (list.isEmpty()) { 168 list.add(new ArrayList<T>()); 169 } 170 171 for (List<T> current : list) { 172 current.add(compound); 173 } 174 } 175 176 @Override 177 public Sequence<T> createSequence(Sequence<F> originalSequence) { 178 Collection<Sequence<T>> sequences = createSequences(originalSequence); 179 if (sequences.size() > 1) { 180 throw new TranslationException("Too many sequences created; " 181 + "createSequence() assumes only one sequence can be created"); 182 } 183 else if (sequences.isEmpty()) { 184 throw new TranslationException("No sequences created"); 185 } 186 return sequences.iterator().next(); 187 } 188 189}