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 022 023package org.biojava.bio; 024 025import org.biojava.utils.ChangeEvent; 026import org.biojava.utils.ChangeForwarder; 027import org.biojava.utils.ChangeSupport; 028import org.biojava.utils.ChangeType; 029import org.biojava.utils.Changeable; 030 031/** 032 * <p>Indicates that an object has an associated annotation.</p> 033 * 034 * <p>Many BioJava objects will have associated unstructured 035 * data. This should be stored in an Annotation instance. However, the 036 * BioJava object itself will probably not want to extend the 037 * Annotation interface directly, but rather delegate off that 038 * functionality to an Annotation property. The Annotatable interface 039 * indicates that there is an Annotation property. When implementing 040 * Annotatable, you should always create a protected or private field 041 * containing an instance of ChangeForwarder, and register it as a 042 * ChangeListener with the associated Annotation delegate 043 * instance.</p> 044 * 045 * <pre> 046 * public class Foo extends AbstractChangeable implements Annotatable { 047 * private Annotation ann; // the associated annotation delegate 048 * protected ChangeForwarder annFor; // the event forwarder 049 * 050 * public Foo() { 051 * // make the ann delegate 052 * ann = new SimpleAnnotation(); 053 * // construct the forwarder so that it emits Annotatable.ANNOTATION ChangeEvents 054 * // for the Annotation.PROPERTY events it will listen for 055 * annFor = new ChangeForwarder.Retyper(this, getChangesupport( Annotatable.ANNOTATION ), 056 * Annotatable.ANNOTATION ); 057 * // connect the forwarder so it listens for Annotation.PROPERTY events 058 * ann.addChangeListener( annFor, Annotation.PROPERTY ); 059 * } 060 * 061 * public Annotation getAnnotation() { 062 * return ann; 063 * } 064 * } 065 * </pre> 066 * Check if BioJava classes and interfaces extend Annotatable. This 067 * will tell you if you should look for associated annotation. 068 * 069 * If an object implements Annotatable, it may well propagate 070 * ChangeEvent notifications from the associated Annotation. You may 071 * need to track these to maintain the state of your applications. 072 * 073 * Be careful to hook up the appropriate event forwarders. 074 * 075 * The getAnnotation() method can be implemented lazily 076 * (instantiate the Annotation instance and event forwarders when the first 077 * request comes in). It can also be implemented by returning throw-away 078 * immutable Annotation instances that are built from scratch each time. 079 * @author Matthew Pocock 080 * @author <a href="mailto:kdj@sanger.ac.uk">Keith James</a> (docs). 081 * @author Kalle N�slund (docs) 082 * @see org.biojavax.RichAnnotatable 083 * @since 1.0 084 */ 085public interface Annotatable extends Changeable { 086 /** 087 * Signals that the associated Annotation has altered in some way. The 088 * chainedEvent property should refer back to the event fired by the 089 * Annotation object. 090 */ 091 public static final ChangeType ANNOTATION = new ChangeType( 092 "the associated annotation has changed", 093 "org.biojava.bio.Annotatable", 094 "ANNOTATION" 095 ); 096 097 /** 098 * Should return the associated annotation object. 099 * 100 * @return an Annotation object, never null 101 */ 102 Annotation getAnnotation(); 103 104 /** 105 * <p>A helper class so that you don't have to worry about 106 * forwarding events from the Annotation object to the Annotatable 107 * one.</p> 108 * 109 * <p>Once a listener is added to your Annotatable that is 110 * interested in ANNOTATION events, then instantiate one of these 111 * and add it as a listener to the annotation object. It will 112 * forward the events to your listeners and translate them 113 * accordingly.</p> This will ease the pain of letting your Annotatable tell its 114 * listeners about changes in the Annotation. 115 * 116 * @author Matthew Pocock 117 * 118 * @deprecated use 119 * <code>new ChangeForwarder.Retyper(source, cs, Annotation.PROPERTY)</code> 120 * instead 121 */ 122 static class AnnotationForwarder extends ChangeForwarder { 123 /** 124 * Create a new AnnotationForwarder that will forward events for a source 125 * using a change support. 126 * 127 * @param source the Object to forward events on behalf of 128 * @param cs the change support that manages listeners 129 */ 130 public AnnotationForwarder(Object source, ChangeSupport cs) { 131 super(source, cs); 132 } 133 134 protected ChangeEvent generateEvent(ChangeEvent ce) { 135 ChangeType ct = ce.getType(); 136 if(ct == Annotation.PROPERTY) { 137 return new ChangeEvent( 138 getSource(), 139 ANNOTATION, 140 ct 141 ); 142 } 143 return null; 144 } 145 } 146}