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.projection; 023 024import java.util.ArrayList; 025import java.util.Iterator; 026import java.util.List; 027 028import org.biojava.bio.BioError; 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.Sequence; 035import org.biojava.bio.seq.impl.TemplateUtils; 036import org.biojava.bio.symbol.IllegalSymbolException; 037import org.biojava.bio.symbol.Location; 038import org.biojava.bio.symbol.SimpleSymbolList; 039import org.biojava.bio.symbol.SymbolList; 040import org.biojava.utils.AssertionFailure; 041import org.biojava.utils.ChangeListener; 042import org.biojava.utils.ChangeType; 043import org.biojava.utils.ChangeVetoException; 044 045/** 046 * Internal class used by ProjectionEngine to wrap Feature objects. 047 * 048 * This is not for you. 049 * 050 * This is the base class that the projection engine extends. If you modify this 051 * you will modify every projected feature. That is probably a bad thing. 052 * 053 * @author Thomas Down 054 * @author Matthew Pocock 055 * @since 1.1 056 */ 057 058public abstract class ProjectedFeature 059 implements 060 Feature, 061 Projection { 062 private final Feature feature; 063 private final ProjectionContext context; 064 065 public ProjectedFeature( 066 Feature f, 067 ProjectionContext ctx 068 ) { 069 this.feature = f; 070 this.context = ctx; 071 } 072 073 public Feature getViewedFeature() { 074 return feature; 075 } 076 077 public ProjectionContext getProjectionContext() { 078 return context; 079 } 080 081 public Sequence getSequence() { 082 return context.getSequence(getViewedFeature()); 083 } 084 085 public FeatureHolder getParent() { 086 return context.getParent(feature); 087 } 088 089 public SymbolList getSymbols() { 090 Location loc = getLocation(); 091 Sequence seq = getSequence(); 092 093 if (loc.isContiguous()) { 094 return seq.subList(loc.getMin(), loc.getMax()); 095 } 096 097 List res = new ArrayList(); 098 for (Iterator i = loc.blockIterator(); i.hasNext();) { 099 Location l = (Location) i.next(); 100 res.add(seq.subList(l.getMin(), l.getMax())); 101 } 102 103 try { 104 return new SimpleSymbolList(seq.getAlphabet(), res); 105 } catch (IllegalSymbolException ex) { 106 throw new BioError(ex); 107 } 108 } 109 110 public int countFeatures() { 111 return getProjectedFeatures().countFeatures(); 112 } 113 114 public boolean containsFeature(Feature f) { 115 return getProjectedFeatures().containsFeature(f); 116 } 117 118 protected FeatureHolder getProjectedFeatures() { 119 return context.projectChildFeatures(feature, this); 120 } 121 122 public Iterator features() { 123 return getProjectedFeatures().features(); 124 } 125 126 public FeatureHolder filter(FeatureFilter ff) { 127 FeatureFilter membershipFilter = new FeatureFilter.And( 128 new FeatureFilter.Not(FeatureFilter.top_level), 129 new FeatureFilter.ContainedByLocation(getLocation())); 130 if (FilterUtils.areDisjoint(ff, membershipFilter)) { 131 return FeatureHolder.EMPTY_FEATURE_HOLDER; 132 } 133 134 return getProjectedFeatures().filter(ff); 135 } 136 137 public FeatureHolder filter(FeatureFilter ff, boolean recurse) { 138 FeatureFilter membershipFilter = 139 new FeatureFilter.ContainedByLocation(getLocation()); 140 if (FilterUtils.areDisjoint(ff, membershipFilter)) { 141 return FeatureHolder.EMPTY_FEATURE_HOLDER; 142 } 143 144 return getProjectedFeatures().filter(ff, recurse); 145 } 146 147 public Feature createFeature(Feature.Template temp) 148 throws ChangeVetoException, BioException { 149 return context.createFeature(feature, temp); 150 } 151 152 public void removeFeature(Feature f) 153 throws ChangeVetoException, BioException { 154 context.removeFeature(feature, f); 155 } 156 157 public Feature.Template makeTemplate() { 158 try { 159 return TemplateUtils.makeTemplate(this); 160 } catch (BioException be) { 161 throw new AssertionFailure("Could not build/populate template for: " + 162 this.toString() + " ", be); 163 } 164 } 165 166 public int hashCode() { 167 return makeTemplate().hashCode(); 168 } 169 170 public boolean equals(Object o) { 171 if (o instanceof Feature) { 172 Feature fo = (Feature) o; 173 if (fo.getSequence().equals(getSequence())) { 174 return makeTemplate().equals(fo.makeTemplate()); 175 } 176 } 177 return false; 178 } 179 180 public void addChangeListener(ChangeListener cl) { 181 addChangeListener(cl, ChangeType.UNKNOWN); 182 } 183 184 public void removeChangeListener(ChangeListener cl) { 185 removeChangeListener(cl, ChangeType.UNKNOWN); 186 } 187 188 public void addChangeListener(ChangeListener cl, ChangeType ct) { 189 context.addChangeListener(feature, cl, ct); 190 } 191 192 public void removeChangeListener(ChangeListener cl, ChangeType ct) { 193 context.removeChangeListener(feature, cl, ct); 194 } 195 196 public boolean isUnchanging(ChangeType ct) { 197 return feature.isUnchanging(ct); 198 } 199}