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.io.Serializable; 025import java.lang.reflect.Constructor; 026import java.lang.reflect.InvocationTargetException; 027import java.util.ArrayList; 028import java.util.Iterator; 029import java.util.List; 030 031import org.biojava.bio.BioException; 032 033/** 034 * FeatureRealizer which uses a lookup table to map template classes 035 * to implementations. Optionally, this implementation can fall back 036 * on another FeatureRealizer if it fails. 037 * 038 * <p> 039 * When searching for a Feature implementation to match a specific 040 * Feature.Template class, the following search order is used: 041 * <ol><li>Mappings added to this SimpleFeatureRealizer, in reverse 042 * order of addition.</li> 043 * <li>Any mappings known to the fallback realizer, if one is installed.</li> 044 * <li>If no mapping can be found, a BioException is thrown.</li></ol> 045 * </p> 046 * 047 * @author Thomas Down 048 */ 049 050public class SimpleFeatureRealizer implements FeatureRealizer, Serializable { 051 private List templateToImpl; 052 private FeatureRealizer fallBack; 053 054 { 055 templateToImpl = new ArrayList(); 056 } 057 058 public SimpleFeatureRealizer() { 059 fallBack = null; 060 } 061 062 public SimpleFeatureRealizer(FeatureRealizer fallBack) { 063 this.fallBack = fallBack; 064 } 065 066 /** 067 * Install a new mapping from a class of Feature.Template to 068 * a class of Feature implementations. The implementation 069 * class MUST have a public constructor of the form 070 * (Sequence, FeatureHolder, Feature.Template). 071 * 072 * <p> 073 * A newly added implementation takes precendence over 074 * any existing implementations if a template can be realized 075 * by more than one implementation. 076 * </p> 077 * 078 * @param template The class of templates to implement. 079 * @param impl A class of Feature which can be used to implement these templates. 080 */ 081 082 public void addImplementation(Class template, Class impl) 083 throws BioException 084 { 085 TemplateImpl ti = new TemplateImpl(template, impl); 086 templateToImpl.add(0, ti); 087 } 088 089 public Feature realizeFeature(Sequence seq, 090 FeatureHolder parent, 091 Feature.Template temp) 092 throws BioException 093 { 094 for (Iterator i = templateToImpl.iterator(); i.hasNext(); ) { 095 TemplateImpl ti = (TemplateImpl) i.next(); 096 if (ti.accept(temp)) 097 return ti.realize(seq, parent, temp); 098 } 099 100 if (fallBack != null) 101 return fallBack.realizeFeature(seq, parent, temp); 102 103 throw new BioException("Couldn't find realized implementation for template of class " + 104 temp.getClass().getName()); 105 } 106 107 private static class TemplateImpl { 108 private Class template; 109 private Constructor cons; 110 111 private TemplateImpl(Class template, Class impl) 112 throws BioException 113 { 114 Class[] signature = new Class[3]; 115 signature[0] = Sequence.class; 116 signature[1] = FeatureHolder.class; 117 signature[2] = template; 118 this.template = template; 119 120 try { 121 this.cons = impl.getConstructor(signature); 122 } catch (NoSuchMethodException ex) { 123 throw new BioException("Class " + impl.getName() + " does not have suitable constructor", ex); 124 } 125 } 126 127 public boolean accept(Feature.Template temp) { 128 return template.isInstance(temp); 129 } 130 131 public Feature realize(Sequence seq, 132 FeatureHolder parent, 133 Feature.Template temp) 134 throws BioException 135 { 136 Object[] consArgs = new Object[3]; 137 consArgs[0] = seq; 138 consArgs[1] = parent; 139 consArgs[2] = temp; 140 try { 141 return (Feature) cons.newInstance(consArgs); 142 } catch (Exception ex) { 143 Throwable t = ex; 144 if(ex instanceof InvocationTargetException) { 145 t = ((InvocationTargetException) ex).getTargetException(); 146 } 147 throw new BioException("Couldn't realize feature", t); 148 } 149 } 150 } 151}