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; 023 024import java.util.Iterator; 025 026import org.biojava.bio.BioException; 027import org.biojava.utils.AbstractChangeable; 028import org.biojava.utils.ChangeEvent; 029import org.biojava.utils.ChangeListener; 030import org.biojava.utils.ChangeSupport; 031import org.biojava.utils.ChangeType; 032import org.biojava.utils.ChangeVetoException; 033 034/** 035 * Wrapper implementation of FeatureHolder which calls a method 036 * to create a contained FeatureHolder on demand. This is an 037 * abstract class and is normally used like: 038 * 039 * FeatureHolder fh = new LazyFeatureHolder() { 040 * protected FeatureHolder createFeatureHolder() { 041 * SimpleFeatureHolder features = new SimpleFeatureHolder(); 042 * // Create some features in here... 043 * return features; 044 * } 045 * } ; 046 * </pre> 047 * 048 * @author Thomas Down 049 * @author Matthew Pocock 050 * @since 1.2 051 * @see org.biojavax.bio.seq.RichFeatureRelationshipHolder 052 */ 053 054public abstract class LazyFeatureHolder 055 extends 056 AbstractChangeable 057 implements 058 FeatureHolder 059{ 060 private FeatureHolder featureHolder; 061 private Forwarder changeForwarder; 062 private FeatureFilter schema; 063 064 /** 065 * Construct a LazyFeatureHolder with the schema of its contained featureholder 066 */ 067 068 protected LazyFeatureHolder() { 069 } 070 071 /** 072 * Construct a LazyFeatureHolder with the specified schema 073 */ 074 075 protected LazyFeatureHolder(FeatureFilter schema) { 076 this.schema = schema; 077 } 078 079 public FeatureFilter getSchema() { 080 if (schema == null) { 081 return getFeatureHolder().getSchema(); 082 } else { 083 return schema; 084 } 085 } 086 087 protected abstract FeatureHolder createFeatureHolder(); 088 089 protected void flushFeatures() { 090 featureHolder = null; 091 } 092 093 private FeatureHolder getFeatureHolder() { 094 if (featureHolder == null) { 095 featureHolder = createFeatureHolder(); 096 097 if (!hasListeners()) { 098 changeForwarder = new Forwarder(); 099 featureHolder.addChangeListener(changeForwarder, ChangeType.UNKNOWN); 100 } 101 } 102 return featureHolder; 103 } 104 105 public Iterator features() { 106 return getFeatureHolder().features(); 107 } 108 109 public int countFeatures() { 110 return getFeatureHolder().countFeatures(); 111 } 112 113 public FeatureHolder filter(FeatureFilter ff) { 114 // FIXME: we need to optimize here 115 return getFeatureHolder().filter(ff); 116 } 117 118 public FeatureHolder filter(FeatureFilter ff, boolean recurse) { 119 if(!recurse) { 120 if(FilterUtils.areDisjoint(ff, getSchema())) { 121 return FeatureHolder.EMPTY_FEATURE_HOLDER; 122 } else if (FilterUtils.areProperSubset(ff, getSchema())) { 123 return this; 124 } 125 } 126 127 // FIXME: There are other optimisations we should be making 128 return getFeatureHolder().filter(ff, recurse); 129 } 130 131 public Feature createFeature(Feature.Template template) 132 throws BioException, ChangeVetoException 133 { 134 return getFeatureHolder().createFeature(template); 135 } 136 137 public void removeFeature(Feature f) 138 throws ChangeVetoException, BioException 139 { 140 getFeatureHolder().removeFeature(f); 141 } 142 143 public boolean containsFeature(Feature f) { 144 return getFeatureHolder().containsFeature(f); 145 } 146 147 protected ChangeSupport getChangeSupport(ChangeType ct) { 148 ChangeSupport changeSupport = super.getChangeSupport(ct); 149 150 if (featureHolder != null) { 151 changeForwarder = new Forwarder(); 152 featureHolder.addChangeListener(changeForwarder, ChangeType.UNKNOWN); 153 } 154 155 return changeSupport; 156 } 157 158 private class Forwarder implements ChangeListener { 159 public void preChange(ChangeEvent cev) 160 throws ChangeVetoException 161 { 162 getChangeSupport(cev.getType()).firePreChangeEvent(cev); 163 } 164 165 public void postChange(ChangeEvent cev) { 166 getChangeSupport(cev.getType()).firePostChangeEvent(cev); 167 } 168 } 169}