Merge branch 'features/JAL-1541_BioJsMSA' into develop
[jalview.git] / src / jalview / datamodel / xdb / embl / EmblEntry.java
index 2ee1fb2..3f890ba 100644 (file)
@@ -1,23 +1,30 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
- * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * This file is part of Jalview.
  * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.datamodel.xdb.embl;
 
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.FeatureProperties;
@@ -26,11 +33,14 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.Vector;
-
+/**
+ * Data model for one entry returned from an EMBL query, as marshalled by a
+ * Castor binding file
+ * 
+ * For example: http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/embl/x53828/emblxml
+ * 
+ * @see embl_mapping.xml
+ */
 public class EmblEntry
 {
   String accession;
@@ -47,13 +57,11 @@ public class EmblEntry
 
   String lastUpdated;
 
-  Vector keywords;
-
-  Vector refs;
+  Vector<String> keywords;
 
-  Vector dbRefs;
+  Vector<DBRefEntry> dbRefs;
 
-  Vector features;
+  Vector<EmblFeature> features;
 
   EmblSequence sequence;
 
@@ -77,7 +85,7 @@ public class EmblEntry
   /**
    * @return the dbRefs
    */
-  public Vector getDbRefs()
+  public Vector<DBRefEntry> getDbRefs()
   {
     return dbRefs;
   }
@@ -86,7 +94,7 @@ public class EmblEntry
    * @param dbRefs
    *          the dbRefs to set
    */
-  public void setDbRefs(Vector dbRefs)
+  public void setDbRefs(Vector<DBRefEntry> dbRefs)
   {
     this.dbRefs = dbRefs;
   }
@@ -111,7 +119,7 @@ public class EmblEntry
   /**
    * @return the features
    */
-  public Vector getFeatures()
+  public Vector<EmblFeature> getFeatures()
   {
     return features;
   }
@@ -120,7 +128,7 @@ public class EmblEntry
    * @param features
    *          the features to set
    */
-  public void setFeatures(Vector features)
+  public void setFeatures(Vector<EmblFeature> features)
   {
     this.features = features;
   }
@@ -128,7 +136,7 @@ public class EmblEntry
   /**
    * @return the keywords
    */
-  public Vector getKeywords()
+  public Vector<String> getKeywords()
   {
     return keywords;
   }
@@ -137,7 +145,7 @@ public class EmblEntry
    * @param keywords
    *          the keywords to set
    */
-  public void setKeywords(Vector keywords)
+  public void setKeywords(Vector<String> keywords)
   {
     this.keywords = keywords;
   }
@@ -160,23 +168,6 @@ public class EmblEntry
   }
 
   /**
-   * @return the refs
-   */
-  public Vector getRefs()
-  {
-    return refs;
-  }
-
-  /**
-   * @param refs
-   *          the refs to set
-   */
-  public void setRefs(Vector refs)
-  {
-    this.refs = refs;
-  }
-
-  /**
    * @return the releaseCreated
    */
   public String getRCreated()
@@ -188,7 +179,7 @@ public class EmblEntry
    * @param releaseCreated
    *          the releaseCreated to set
    */
-  public void setRcreated(String releaseCreated)
+  public void setRCreated(String releaseCreated)
   {
     this.rCreated = releaseCreated;
   }
@@ -423,9 +414,13 @@ public class EmblEntry
       { 1, dna.getLength() }, 1, 1));
       // TODO: transform EMBL Database refs to canonical form
       if (dbRefs != null)
+      {
         for (Iterator i = dbRefs.iterator(); i.hasNext(); dna
                 .addDBRef((DBRefEntry) i.next()))
+        {
           ;
+        }
+      }
     }
     try
     {
@@ -438,7 +433,9 @@ public class EmblEntry
           {
             for (Iterator dbr = feature.dbRefs.iterator(); dbr.hasNext(); dna
                     .addDBRef((DBRefEntry) dbr.next()))
+            {
               ;
+            }
           }
         }
         if (FeatureProperties.isCodingFeature(sourceDb, feature.getName()))
@@ -454,7 +451,9 @@ public class EmblEntry
             {
               for (Iterator dbr = feature.dbRefs.iterator(); dbr.hasNext(); dna
                       .addDBRef((DBRefEntry) dbr.next()))
+              {
                 ;
+              }
             }
           }
         }
@@ -580,16 +579,17 @@ public class EmblEntry
       }
     }
     Sequence product = null;
+    DBRefEntry protEMBLCDS = null;
     exon = adjustForPrStart(prstart, exon);
+    boolean noProteinDbref=true;
     
     if (prseq != null && prname != null && prid != null)
     {
       // extract proteins.
       product = new Sequence(prid, prseq, 1, prseq.length());
-      product
-              .setDescription(((prname.length() == 0) ? "Protein Product from "
-                      + sourceDb
-                      : prname));
+      product.setDescription(((prname.length() == 0) ? "Protein Product from "
+              + sourceDb
+              : prname));
       if (!noPeptide)
       {
         // Protein is also added to vector of sequences returned
@@ -602,7 +602,7 @@ public class EmblEntry
         System.err
                 .println("Implementation Notice: EMBLCDS records not properly supported yet - Making up the CDNA region of this sequence... may be incorrect ("
                         + sourceDb + ":" + getAccession() + ")");
-        if (prseq.length() * 3 == (1-prstart + dna.getSequence().length))
+        if (prseq.length() * 3 == (1 - prstart + dna.getSequence().length))
         {
           System.err
                   .println("Not allowing for additional stop codon at end of cDNA fragment... !");
@@ -613,7 +613,7 @@ public class EmblEntry
           map = new jalview.datamodel.Mapping(product, exon, new int[]
           { 1, prseq.length() }, 3, 1);
         }
-        if ((prseq.length() + 1) * 3 == (1-prstart + dna.getSequence().length))
+        if ((prseq.length() + 1) * 3 == (1 - prstart + dna.getSequence().length))
         {
           System.err
                   .println("Allowing for additional stop codon at end of cDNA fragment... will probably cause an error in VAMSAs!");
@@ -625,9 +625,9 @@ public class EmblEntry
       }
       else
       {
-        // Trim the exon mapping if necessary - the given product may only be a fragment of a larger protein. (EMBL:AY043181 is an example)
-        
-        
+        // Trim the exon mapping if necessary - the given product may only be a
+        // fragment of a larger protein. (EMBL:AY043181 is an example)
+
         if (isEmblCdna)
         {
           // TODO: Add a DbRef back to the parent EMBL sequence with the exon
@@ -639,27 +639,33 @@ public class EmblEntry
         else
         {
           // final product length trunctation check
-          
-          map = new jalview.datamodel.Mapping(product, adjustForProteinLength(prseq.length(),exon), new int[]
-          { 1, prseq.length() }, 3, 1);
+
+          map = new jalview.datamodel.Mapping(product,
+                  adjustForProteinLength(prseq.length(), exon), new int[]
+                  { 1, prseq.length() }, 3, 1);
           // reconstruct the EMBLCDS entry
-          // TODO: this is only necessary when there codon annotation is complete (I think JBPNote)
+          // TODO: this is only necessary when there codon annotation is
+          // complete (I think JBPNote)
           DBRefEntry pcdnaref = new DBRefEntry();
           pcdnaref.setAccessionId(prid);
           pcdnaref.setSource(DBRefSource.EMBLCDS);
           pcdnaref.setVersion(getVersion()); // same as parent EMBL version.
           jalview.util.MapList mp = new jalview.util.MapList(new int[]
-          { 1, prseq.length() },
-                  new int[]
-                  { 1 + (prstart - 1),
-                      (prstart - 1) + 3 * prseq.length() }, 1, 3);
+          { 1, prseq.length() }, new int[]
+          { 1 + (prstart - 1), (prstart - 1) + 3 * prseq.length() }, 1, 3);
           // { 1 + (prstart - 1) * 3,
           // 1 + (prstart - 1) * 3 + prseq.length() * 3 - 1 }, new int[]
           // { 1prstart, prstart + prseq.length() - 1 }, 3, 1);
           pcdnaref.setMap(new Mapping(mp));
           if (product != null)
+          {
             product.addDBRef(pcdnaref);
-
+            protEMBLCDS = new DBRefEntry(pcdnaref);
+            protEMBLCDS.setSource(DBRefSource.EMBLCDSProduct);
+            product.addDBRef(protEMBLCDS);
+            
+          }     
+          
         }
       }
       // add cds feature to dna seq - this may include the stop codon
@@ -670,18 +676,20 @@ public class EmblEntry
         sf.setEnd(exon[xint + 1]);
         sf.setType(feature.getName());
         sf.setFeatureGroup(sourceDb);
-        sf.setDescription("Exon " + (1 + (int) (xint / 2))
+        sf.setDescription("Exon " + (1 + xint / 2)
                 + " for protein '" + prname + "' EMBLCDS:" + prid);
         sf.setValue(FeatureProperties.EXONPOS, new Integer(1 + xint));
         sf.setValue(FeatureProperties.EXONPRODUCT, prname);
         if (vals != null && vals.size() > 0)
         {
-          Enumeration kv = vals.elements();
+          Enumeration kv = vals.keys();
           while (kv.hasMoreElements())
           {
             Object key = kv.nextElement();
             if (key != null)
+            {
               sf.setValue(key.toString(), vals.get(key));
+            }
           }
         }
         dna.addSequenceFeature(sf);
@@ -711,19 +719,20 @@ public class EmblEntry
                               + ref.getAccessionId());
             }
           }
+          noProteinDbref = false;
         }
         if (product != null)
         {
-          DBRefEntry pref = new DBRefEntry(ref.getSource(), ref
-                  .getVersion(), ref.getAccessionId());
+          DBRefEntry pref = new DBRefEntry(ref.getSource(),
+                  ref.getVersion(), ref.getAccessionId());
           pref.setMap(null); // reference is direct
           product.addDBRef(pref);
           // Add converse mapping reference
           if (map != null)
           {
             Mapping pmap = new Mapping(dna, map.getMap().getInverse());
-            pref = new DBRefEntry(sourceDb, getVersion(), this
-                    .getAccession());
+            pref = new DBRefEntry(sourceDb, getVersion(),
+                    this.getAccession());
             pref.setMap(pmap);
             if (map.getTo() != null)
             {
@@ -733,6 +742,33 @@ public class EmblEntry
         }
         dna.addDBRef(ref);
       }
+      if (noProteinDbref && product != null)
+      {
+        // add protein coding reference to dna sequence so xref matches
+        if (protEMBLCDS == null)
+        {
+          protEMBLCDS = new DBRefEntry();
+          protEMBLCDS.setAccessionId(prid);
+          protEMBLCDS.setSource(DBRefSource.EMBLCDSProduct);
+          protEMBLCDS.setVersion(getVersion());
+          protEMBLCDS
+                  .setMap(new Mapping(product, map.getMap().getInverse()));
+        }
+        product.addDBRef(protEMBLCDS);
+          
+        // Add converse mapping reference
+        if (map != null)
+        {
+          Mapping pmap = new Mapping(product, protEMBLCDS.getMap().getMap()
+                  .getInverse());
+          DBRefEntry ncMap = new DBRefEntry(protEMBLCDS);
+          ncMap.setMap(pmap);
+          if (map.getTo() != null)
+          {
+            dna.addDBRef(ncMap);
+          }
+        }
+      }
     }
   }
 
@@ -770,8 +806,10 @@ public class EmblEntry
     }
     return exon;
   }
+
   /**
-   * truncate the last exon interval to the prlength'th codon 
+   * truncate the last exon interval to the prlength'th codon
+   * 
    * @param prlength
    * @param exon
    * @return new exon
@@ -779,15 +817,15 @@ public class EmblEntry
   private int[] adjustForProteinLength(int prlength, int[] exon)
   {
 
-    int origxon[], sxpos = -1,endxon=0,cdslength=prlength*3;
+    int origxon[], sxpos = -1, endxon = 0, cdslength = prlength * 3;
     int sxstart, sxstop; // unnecessary variables used for debugging
     // first adjust range for codon start attribute
-    if (prlength >= 1 && exon!=null)
+    if (prlength >= 1 && exon != null)
     {
       origxon = new int[exon.length];
       System.arraycopy(exon, 0, origxon, 0, exon.length);
       int cdspos = 0;
-      for (int x = 0; x < exon.length && sxpos==-1; x += 2)
+      for (int x = 0; x < exon.length && sxpos == -1; x += 2)
       {
         cdspos += exon[x + 1] - exon[x] + 1;
         if (cdslength <= cdspos)
@@ -796,21 +834,25 @@ public class EmblEntry
           sxpos = x;
           sxstart = exon[x];
           sxstop = exon[x + 1];
-          if (cdslength!=cdspos) {
-            System.err.println("Truncating final exon interval on region by "+(cdspos-cdslength));
+          if (cdslength != cdspos)
+          {
+            System.err
+                    .println("Truncating final exon interval on region by "
+                            + (cdspos - cdslength));
           }
           // locate the new end boundary of final exon as endxon
-          endxon = exon[x+1] - cdspos + cdslength;
+          endxon = exon[x + 1] - cdspos + cdslength;
           break;
         }
       }
 
-      if (sxpos !=-1)
+      if (sxpos != -1)
       {
         // and trim the exon interval set if necessary
-        int[] nxon = new int[sxpos+2];
-        System.arraycopy(exon, 0, nxon, 0, sxpos+2);
-        nxon[sxpos+1] = endxon; // update the end boundary for the new exon set
+        int[] nxon = new int[sxpos + 2];
+        System.arraycopy(exon, 0, nxon, 0, sxpos + 2);
+        nxon[sxpos + 1] = endxon; // update the end boundary for the new exon
+                                  // set
         exon = nxon;
       }
     }