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}