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.ArrayList;
025import java.util.List;
026
027import org.biojava.bio.BioException;
028import org.biojava.bio.seq.db.IllegalIDException;
029import org.biojava.bio.symbol.Location;
030
031/**
032 * A feature that indicates that there is some remote feature that can't be
033 * represented entirely on a single Sequence.
034 * <p>
035 * These are the sort of features that represent things like the horible Embl
036 * remote feature spans (such as AL24199:100..200). The method getRemoteFeature
037 * should return a Feature on another Sequence that properly represents the
038 * Location. This Seqeunce will often be an Assembly of the parent Sequence to
039 * this Feature, and the Sequence associated with the remote Location sequence
040 * ID. Thse Features are also applicable to the case when a portion of a
041 * Sequence is projected but some Feature overlaps the boundary of the projected
042 * portion.
043 *
044 * @see org.biojavax.bio.seq.RichFeature
045 * @author Matthew Pocock
046 * @author Greg Cox
047 * @since 1.2
048 */
049public interface RemoteFeature extends StrandedFeature {
050  /**
051   * Retrieve the list of Regions that locate this feature both localy and
052   * remotely. Local Regions have a null sequence ID.
053   *
054   * @return an immutable List of Regions
055   */
056  List getRegions();
057
058  /**
059   * Retrieve the Feature on some assembly Sequence that can represent this
060   * RemoteFeature properly.
061   * <p>
062   * This method should be equivalent to calling
063   * <code>getResolver().resolve(this)</code>.
064   *
065   * @return the Feature on another Sequence that this is projected onto
066   * @throws BioException if for any reason the remote Feature could not be
067   *            constructed
068   */
069  Feature getRemoteFeature() throws BioException;
070
071  Resolver getResolver();
072
073  public class Template extends StrandedFeature.Template {
074    public List regions;
075    public Resolver resolver;
076
077    public Template() {
078      super();
079      location = Location.empty;
080      regions = new ArrayList();
081      resolver = null;
082    }
083
084    /**
085     * Creates a RemoteFeature.Template that has the same values as the
086     * template passed in.  Fields that are in the template passed in but
087     * not in RemoteFeature Templates will be silently discarded.  Regions is
088     * set to an empty list and the resolver is set to null.
089     *
090     * @param theTemplate the template for this template.
091     */
092    public Template(Feature.Template theTemplate) {
093      location = theTemplate.location;
094      if (location == null) {
095        location = Location.empty;
096      }
097      type = theTemplate.type;
098      source = theTemplate.source;
099      annotation = theTemplate.annotation;
100      if (theTemplate instanceof StrandedFeature.Template) {
101        strand = ((StrandedFeature.Template) theTemplate).strand;
102      } else {
103        strand = StrandedFeature.UNKNOWN;
104      }
105      resolver = null;
106      regions = null;
107    }
108
109  }
110
111  /**
112   * The interface for objects that actually can take a RemoteFeature and
113   * return a Sequence object with the feature resolved into a real feature.
114   * <p>
115   * An implementation may choose to create a new Assembly from Sequences
116   * in a SequenceDB instance, or to return some existing larger Sequence that
117   * the sequence parent of the Feature is part of. This interface should ensure
118   * canonicalization of the returned Feature and the Sequence it resides on
119   * (using, for instance, SoftReferenceCacheMap keyed by a set of sequence
120   * IDs).
121   *
122   * @author Matthew Pocock
123   * @since 1.1
124   */
125  public static interface Resolver {
126    /**
127     * Resolve rFeat.
128     * <p>
129     * This method returns a Feature that represents the RemoteFeature rFeat on
130     * some Sequence where all of the Regions can be represented localy. This
131     * may be an assembly of the parent sequence of rFeat and each of the
132     * Sequences that have IDs listed in the Region list of rFeat.
133     *
134     * @param rFeat  the RemoteFeature to resolve
135     * @return a Feature on some other Seqence where each Region of rFeat is
136     *          resolved into a local Location
137     */
138    Feature resolve(RemoteFeature rFeat) throws IllegalIDException, BioException;
139  }
140
141  /**
142   * A tuple of Location and sequence ID.
143   * <p>
144   * For local locations, the Region is just a wrapper for a Location. For
145   * remote Regions, it also contains a String representing the Sequence ID of
146   * the remote Location.
147   *
148   * @author Matthew Pocock
149   * @since 1.1
150   */
151  public final static class Region {
152    private final Location location;
153    private final String seqID;
154    private final boolean isRemote;
155
156    /**
157     * Create a new Region.
158     *
159     * @param location  the Location of the Region
160     * @param seqID the ID of the Sequence containing the Location, or null if
161     *          it is a local Region
162     */
163    public Region(Location location, String seqID, boolean isRemote) {
164      this.location = location;
165      this.seqID = seqID;
166      this.isRemote = isRemote;
167    }
168
169    /**
170     * Retrieve the Location of the Region.
171     *
172     * @return the Location of this Region
173     */
174    public Location getLocation() {
175      return location;
176    }
177
178    /**
179     * Return the remote Sequence ID if this Region is on another Sequence
180     * (isRemote will return true), null otherwise.
181     *
182     * @return the ID of the remote Sequence containing this Region
183     */
184    public String getSeqID() {
185      return seqID;
186    }
187
188    /**
189     * Return whether this Region is remote or local.
190     * <p>
191     * If this returns true, getSeqID() will return the ID of the remote
192     * sequence. Otherwise, getSeqID() will return null.
193     *
194     * @return true if this is a remote Region, false otherwise
195     */
196    public boolean isRemote() {
197      return isRemote;
198    }
199  }
200}