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 * Created on 01-21-2010 021 */ 022 023package org.biojava.nbio.core.sequence.features; 024 025import org.biojava.nbio.core.sequence.location.template.AbstractLocation; 026import org.biojava.nbio.core.sequence.template.AbstractSequence; 027import org.biojava.nbio.core.sequence.template.Compound; 028 029import java.util.ArrayList; 030import java.util.Comparator; 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; 034 035/** 036 * A feature is currently any descriptive item that can be associated with a sequence position(s) 037 * A feature has a type and a source which is currently a string to allow flexibility for the user 038 * Ideally well defined features should have a class to describe attributes of that feature 039 * @author Scooter Willis <willishf at gmail dot com> 040 */ 041public abstract class AbstractFeature<S extends AbstractSequence<C>, C extends Compound> 042 implements FeatureInterface<S, C> { 043 List<FeatureInterface<S, C>> childrenFeatures = new ArrayList<FeatureInterface<S, C>>(); 044 FeatureInterface<S, C> parentFeature; 045 AbstractLocation sequenceLocation; 046 String type = ""; 047 String source = ""; 048 private String description = ""; 049 private String shortDescription = ""; 050 private Object userObject = null; 051 private Map<String, List<Qualifier>> Qualifiers = new HashMap<String, List<Qualifier>>(); 052 053 /** 054 * A feature has a type and a source 055 * @param type 056 * @param source 057 */ 058 public AbstractFeature(String type,String source){ 059 this.type = type; 060 this.source = source; 061 } 062 063 /** 064 * A feature could be a single sequence position like a mutation or a post translational modification of an amino acid. 065 * It could also be the docking interface of N number of amino acids on the surface. The location wold then be a collection 066 * of sequence positions instead of a single sequence position or the begin and end of a sequence segment. 067 * @return 068 */ 069 070 @Override 071 public AbstractLocation getLocations() { 072 return sequenceLocation; 073 } 074 075 /** 076 * A feature could be a single sequence position like a mutation or a post translational modification of an amino acid. 077 * It could also be the docking interface of N number of amino acids on the surface. The location wold then be a collection 078 * of sequence positions instead of a single sequence position or the begin and end of a sequence segment. 079 * @param loc 080 */ 081 @Override 082 public void setLocation(AbstractLocation loc) { 083 sequenceLocation = loc; 084 } 085 086 /** 087 * The feature type 088 * @return 089 */ 090 @Override 091 public String getType() { 092 return type; 093 } 094 095 /** 096 * Set the feature type 097 * @param type 098 */ 099 @Override 100 public void setType(String type) { 101 this.type = type; 102 } 103 104 /** 105 * The feature source 106 * @return 107 */ 108 109 @Override 110 public String getSource() { 111 return source; 112 } 113 114 /** 115 * Set the feature source 116 * @param source 117 */ 118 @Override 119 public void setSource(String source) { 120 this.source = source; 121 } 122 123 /** 124 * A feature can be the child or contained by a parent feature. An example is a Helix feature could contain 125 * children features. A PFAM domain could contain secondary structures. 126 * @param feature 127 */ 128 @Override 129 public void setParentFeature(FeatureInterface<S, C> feature) { 130 parentFeature = feature; 131 } 132 133 /** 134 * Get the parent Feature 135 * @return 136 */ 137 @Override 138 public FeatureInterface<S, C> getParentFeature() { 139 return parentFeature; 140 } 141 142 /** 143 * Get the children features 144 * @return 145 */ 146 @Override 147 public List<FeatureInterface<S, C>> getChildrenFeatures() { 148 return childrenFeatures; 149 } 150 151 /** 152 * Set the children features 153 * @param features 154 */ 155 @Override 156 public void setChildrenFeatures(List<FeatureInterface<S, C>> features) { 157 childrenFeatures = features; 158 159 } 160 161 /** 162 * @return the description 163 */ 164 @Override 165 public String getDescription() { 166 return description; 167 } 168 169 /** 170 * @param description the description to set 171 */ 172 @Override 173 public void setDescription(String description) { 174 this.description = description; 175 } 176 177 /** 178 * @return the shortDescription 179 */ 180 @Override 181 public String getShortDescription() { 182 return shortDescription; 183 } 184 185 /** 186 * @param shortDescription the shortDescription to set 187 */ 188 @Override 189 public void setShortDescription(String shortDescription) { 190 this.shortDescription = shortDescription; 191 } 192 193 /** 194 * Sort features by start position and then longest length. When features are added 195 * having them sorted by start position and then longest length helps on the layout 196 * of overlapping features so they are delivered in a proper order. 197 */ 198 199 public static final Comparator<FeatureInterface<?, ?>> LOCATION_LENGTH = new Comparator<FeatureInterface<?, ?>>() { 200 201 @Override 202 public int compare(FeatureInterface<?, ?> e1, FeatureInterface<?, ?> e2) { 203 double v1 = e1.getLocations().getStart().getPosition(); 204 double v2 = e2.getLocations().getStart().getPosition(); 205 if (v1 < v2) { 206 return -1; 207 } else if (v1 > v2) { 208 return 1; 209 } else { 210 double end1 = e1.getLocations().getEnd().getPosition(); 211 double end2 = e2.getLocations().getEnd().getPosition(); 212 if(end1 > end2) 213 return -1; 214 else if(end1 < end2) 215 return 1; 216 else 217 return 0; 218 } 219 220 } 221 }; 222 223 /** 224 * Sort features by length. //TODO need to handle cases where features have multiple locations, strand etc 225 * 226 */ 227 228 static public final Comparator<FeatureInterface<?, ?>> LENGTH = new Comparator<FeatureInterface<?, ?>>() { 229 230 @Override 231 public int compare(FeatureInterface<?, ?> e1, FeatureInterface<?, ?> e2) { 232 double v1 = Math.abs(e1.getLocations().getEnd().getPosition()- e1.getLocations().getStart().getPosition()); 233 double v2 = Math.abs(e2.getLocations().getEnd().getPosition() - e2.getLocations().getStart().getPosition()); 234 if (v1 < v2) { 235 return -1; 236 } else if (v1 > v2) { 237 return 1; 238 } else { 239 return 0; 240 } 241 242 } 243 }; 244 245 /** 246 * Sort features by type 247 */ 248 public static final Comparator<FeatureInterface<?, ?>> TYPE = new Comparator<FeatureInterface<?, ?>>() { 249 250 @Override 251 public int compare(FeatureInterface<?, ?> o1, FeatureInterface<?, ?> o2) { 252 return o1.getType().compareTo(o2.getType()); 253 } 254 }; 255 256 /** 257 * @return the userObject 258 */ 259 @Override 260 public Object getUserObject() { 261 return userObject; 262 } 263 264 /** 265 * Allow the user to associate an object with the feature. This way if a feature which is displayed in a GUI 266 * is clicked on the application can then get a user defined object associated with the feature. 267 * @param userObject the userObject to set 268 */ 269 @Override 270 public void setUserObject(Object userObject) { 271 this.userObject = userObject; 272 } 273 274 @Override 275 public Map<String, List<Qualifier>> getQualifiers() { 276 // TODO Auto-generated method stub 277 return Qualifiers; 278 } 279 280 @Override 281 public void setQualifiers(Map<String, List<Qualifier>> qualifiers) { 282 // TODO Auto-generated method stub 283 Qualifiers = qualifiers; 284 285 } 286 287 @Override 288 public void addQualifier(String key, Qualifier qualifier) { 289 // Check for key. Update list of values 290 if (Qualifiers.containsKey(key)){ 291 List<Qualifier> vals = Qualifiers.get(key); 292 vals.add(qualifier); 293 Qualifiers.put(key, vals); 294 } else { 295 List<Qualifier> vals = new ArrayList<Qualifier>(); 296 vals.add(qualifier); 297 Qualifiers.put(key, vals); 298 } 299 300 } 301 302}