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.seq.io; 023 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.List; 029import java.util.Set; 030 031import org.biojava.bio.Annotation; 032import org.biojava.bio.BioError; 033import org.biojava.bio.BioException; 034import org.biojava.bio.SimpleAnnotation; 035import org.biojava.bio.SmallAnnotation; 036import org.biojava.bio.seq.Feature; 037import org.biojava.bio.seq.Sequence; 038import org.biojava.bio.symbol.Alphabet; 039import org.biojava.bio.symbol.IllegalAlphabetException; 040import org.biojava.bio.symbol.Symbol; 041import org.biojava.utils.ChangeVetoException; 042 043/** 044 * Basic SequenceBuilder implementation which accumulates all 045 * notified information. Subclass this to implement specific 046 * Sequence implementations. 047 * 048 * More functionality is offered by the 049 * {@link org.biojavax.bio.seq.io.SimpleRichSequenceBuilder SimpleRichSequenceBuilder}. 050 * 051 * @author Thomas Down 052 * @author David Huen (modified SimpleSequence to make this) 053 * @version 1.2 [newio proposal] 054 * 055 */ 056 057public abstract class SequenceBuilderBase implements SequenceBuilder { 058 public static Object ERROR_FEATURES_PROPERTY 059 = SequenceBuilderBase.class + "ERROR_FEATURES_PROPERTY"; 060 061 // 062 // State 063 // 064 065 protected String name; 066 protected String uri; 067 068 // annotation on the sequence itself 069 protected Annotation annotation; 070 071 // features directly attached to sequence 072 private Set rootFeatures; 073 074 private List featureStack; 075 076 protected Sequence seq; 077 078 { 079 annotation = new SimpleAnnotation(); 080 rootFeatures = new HashSet(); 081 featureStack = new ArrayList(); 082// slBuilder = new ChunkedSymbolListBuilder(); 083 } 084 085 // 086 // SeqIOListener 087 // 088 089 public void startSequence() { 090 } 091 092 public void endSequence() { 093 } 094 095 public void setName(String name) { 096 this.name = name; 097 } 098 099 public void setURI(String uri) { 100 this.uri = uri; 101 } 102 103 public abstract void addSymbols(Alphabet alpha, Symbol[] syms, int pos, int len) 104 throws IllegalAlphabetException; 105 106 /** 107 * Add an annotation-bundle entry to the sequence. If the annotation key 108 * isn't currently defined, the value is added directly. Otherwise: 109 * 110 * <ul> 111 * <li> If the current value implements the Collection interface, 112 * the new value is added to that collection. </li> 113 * <li> Otherwise, the current value is replaced by a List object 114 * containing the old value then the new value in that order. </li> 115 * </ul> 116 */ 117 public void addSequenceProperty(Object key, Object value) { 118 addProperty(annotation, key, value); 119 } 120 121 public void startFeature(Feature.Template templ) { 122 TemplateWithChildren t2 = new TemplateWithChildren(); 123 t2.template = templ; 124 if(templ.annotation == Annotation.EMPTY_ANNOTATION) { 125 templ.annotation = new SmallAnnotation(); 126 } 127 int stackSize = featureStack.size(); 128 if (stackSize == 0) { 129 rootFeatures.add(t2); 130 } else { 131 TemplateWithChildren parent = (TemplateWithChildren) featureStack.get(stackSize - 1); 132 if (parent.children == null) 133 parent.children = new HashSet(); 134 parent.children.add(t2); 135 } 136 featureStack.add(t2); 137 } 138 139 /** 140 * Add an annotation-bundle entry to the feature. If the annotation key 141 * isn't currently defined, the value is added directly. Otherwise: 142 * 143 * <ul> 144 * <li> If the current value implements the Collection interface, 145 * the new value is added to that collection. </li> 146 * <li> Otherwise, the current value is replaced by a List object 147 * containing the old value then the new value in that order. </li> 148 * </ul> 149 */ 150 public void addFeatureProperty(Object key, Object value) 151 throws ParseException { 152 try { 153 int stackSize = featureStack.size(); 154 155 TemplateWithChildren top = 156 (TemplateWithChildren) featureStack.get(stackSize - 1); 157 158 addProperty(top.template.annotation, key, value); 159 } catch (IndexOutOfBoundsException ioobe) { 160 throw new ParseException( 161 ioobe, 162 "Attempted to add annotation to a feature when no startFeature " + 163 "had been invoked" 164 ); 165 } 166 } 167 168 public void endFeature() { 169 if (featureStack.size() == 0) 170 throw new BioError("Assertion failed: Not within a feature"); 171 featureStack.remove(featureStack.size() - 1); 172 } 173 174 public Sequence makeSequence() 175 throws BioException 176 { 177 // SymbolList symbols = slBuilder.makeSymbolList(); 178 // Sequence seq = new SimpleSequence(symbols, uri, name, annotation); 179 try { 180 for (Iterator i = rootFeatures.iterator(); i.hasNext(); ) { 181 TemplateWithChildren twc = (TemplateWithChildren) i.next(); 182 try { 183 Feature f = seq.createFeature(twc.template); 184 if (twc.children != null) { 185 makeChildFeatures(f, twc.children); 186 } 187 } catch (Exception e) { 188 // fixme: we should do something more sensible with this error 189 e.printStackTrace(); 190 Set errFeatures; 191 Annotation ann = seq.getAnnotation(); 192 if(ann.containsProperty(ERROR_FEATURES_PROPERTY)) { 193 errFeatures = (Set) ann.getProperty(ERROR_FEATURES_PROPERTY); 194 } else { 195 ann.setProperty( 196 ERROR_FEATURES_PROPERTY, 197 errFeatures = new HashSet() 198 ); 199 } 200 errFeatures.add(twc); 201 } 202 } 203 } catch (Exception ex) { 204 throw new BioError("Couldn't create feature",ex); 205 } 206 return seq; 207 } 208 209 private void makeChildFeatures(Feature parent, Set children) 210 throws Exception 211 { 212 for (Iterator i = children.iterator(); i.hasNext(); ) { 213 TemplateWithChildren twc = (TemplateWithChildren) i.next(); 214 Feature f = parent.createFeature(twc.template); 215 if (twc.children != null) { 216 makeChildFeatures(f, twc.children); 217 } 218 } 219 } 220 221 protected void addProperty(Annotation ann, Object key, Object value) { 222 if (value == null) 223 return; 224 225 Object oldValue = null; 226 Object newValue = value; 227 228 if(ann.containsProperty(key)) { 229 oldValue = ann.getProperty(key); 230 } 231 232 if (oldValue != null) { 233 if (oldValue instanceof Collection) { 234 ((Collection) oldValue).add(newValue); 235 newValue = oldValue; 236 } else { 237 List nvList = new ArrayList(); 238 nvList.add(oldValue); 239 nvList.add(newValue); 240 newValue = nvList; 241 } 242 } 243 244 try { 245 ann.setProperty(key, newValue); 246 } catch (ChangeVetoException ex) { 247 throw new BioError("Annotation should be modifiable",ex); 248 } 249 } 250 251 private static class TemplateWithChildren { 252 Feature.Template template; 253 Set children; 254 } 255}