JAL-3116 Uniprot XML unmarshalled using JAXB not Castor
[jalview.git] / src / jalview / datamodel / xdb / embl / EmblEntry.java
index a0e1234..bbe6a20 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.datamodel.xdb.embl;
 
 import jalview.analysis.SequenceIdMatcher;
+import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.FeatureProperties;
@@ -34,6 +35,7 @@ import jalview.util.MapList;
 import jalview.util.MappingUtils;
 import jalview.util.StringUtils;
 
+import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Hashtable;
 import java.util.List;
@@ -46,9 +48,7 @@ import java.util.regex.Pattern;
  * 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?db=ena_sequence&id=J03321
- * &format=emblxml
+ * For example: http://www.ebi.ac.uk/ena/data/view/J03321&display=xml
  * 
  * @see embl_mapping.xml
  */
@@ -185,43 +185,42 @@ public class EmblEntry
    */
   public SequenceI getSequence(String sourceDb, List<SequenceI> peptides)
   {
-    SequenceI dna = new Sequence(sourceDb + "|" + accession,
-            sequence.getSequence());
+    SequenceI dna = makeSequence(sourceDb);
+    if (dna == null)
+    {
+      return null;
+    }
     dna.setDescription(description);
-    DBRefEntry retrievedref = new DBRefEntry(sourceDb,
-            getSequenceVersion(), accession);
+    DBRefEntry retrievedref = new DBRefEntry(sourceDb, getSequenceVersion(),
+            accession);
     dna.addDBRef(retrievedref);
     // add map to indicate the sequence is a valid coordinate frame for the
     // dbref
-    retrievedref.setMap(new Mapping(null, new int[] { 1, dna.getLength() },
-            new int[] { 1, dna.getLength() }, 1, 1));
-    // TODO: transform EMBL Database refs to canonical form
+    retrievedref
+            .setMap(new Mapping(null, new int[]
+            { 1, dna.getLength() }, new int[] { 1, dna.getLength() }, 1,
+                    1));
+
+    /*
+     * transform EMBL Database refs to canonical form
+     */
     if (dbRefs != null)
     {
       for (DBRefEntry dbref : dbRefs)
       {
+        dbref.setSource(DBRefUtils.getCanonicalName(dbref.getSource()));
         dna.addDBRef(dbref);
       }
     }
 
+    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
     try
     {
       for (EmblFeature feature : features)
       {
-        if (feature.dbRefs != null)
-        {
-          for (DBRefEntry dbref : feature.dbRefs)
-          {
-            /*
-             * convert UniProtKB/Swiss-Prot to UNIPROT
-             */
-            dbref.setSource(DBRefUtils.getCanonicalName(dbref.getSource()));
-            dna.addDBRef(dbref);
-          }
-        }
         if (FeatureProperties.isCodingFeature(sourceDb, feature.getName()))
         {
-          parseCodingFeature(feature, sourceDb, dna, peptides);
+          parseCodingFeature(feature, sourceDb, dna, peptides, matcher);
         }
       }
     } catch (Exception e)
@@ -238,6 +237,23 @@ public class EmblEntry
   }
 
   /**
+   * @param sourceDb
+   * @return
+   */
+  SequenceI makeSequence(String sourceDb)
+  {
+    if (sequence == null)
+    {
+      System.err.println(
+              "No sequence was returned for ENA accession " + accession);
+      return null;
+    }
+    SequenceI dna = new Sequence(sourceDb + "|" + accession,
+            sequence.getSequence());
+    return dna;
+  }
+
+  /**
    * Extracts coding region and product from a CDS feature and properly decorate
    * it with annotations.
    * 
@@ -249,19 +265,21 @@ public class EmblEntry
    *          parent dna sequence for this record
    * @param peptides
    *          list of protein product sequences for Embl entry
+   * @param matcher
+   *          helper to match xrefs in already retrieved sequences
    */
   void parseCodingFeature(EmblFeature feature, String sourceDb,
-          SequenceI dna, List<SequenceI> peptides)
+          SequenceI dna, List<SequenceI> peptides,
+          SequenceIdMatcher matcher)
   {
     boolean isEmblCdna = sourceDb.equals(DBRefSource.EMBLCDS);
 
-    int[] exon = getCdsRanges(feature);
+    int[] exons = getCdsRanges(feature);
 
-    String prseq = null;
-    String prname = "";
-    String prid = null;
-    Map<String, String> vals = new Hashtable<String, String>();
-    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
+    String translation = null;
+    String proteinName = "";
+    String proteinId = null;
+    Map<String, String> vals = new Hashtable<>();
 
     /*
      * codon_start 1/2/3 in EMBL corresponds to phase 0/1/2 in CDS
@@ -281,27 +299,28 @@ public class EmblEntry
         if (qname.equals("translation"))
         {
           // remove all spaces (precompiled String.replaceAll(" ", ""))
-          prseq = SPACE_PATTERN.matcher(q.getValues()[0]).replaceAll("");
+          translation = SPACE_PATTERN.matcher(q.getValues()[0])
+                  .replaceAll("");
         }
         else if (qname.equals("protein_id"))
         {
-          prid = q.getValues()[0];
+          proteinId = q.getValues()[0].trim();
         }
         else if (qname.equals("codon_start"))
         {
           try
           {
-            codonStart = Integer.parseInt(q.getValues()[0]);
+            codonStart = Integer.parseInt(q.getValues()[0].trim());
           } catch (NumberFormatException e)
           {
-            System.err.println("Invalid codon_start in XML for "
-                    + accession + ": " + e.getMessage());
+            System.err.println("Invalid codon_start in XML for " + accession
+                    + ": " + e.getMessage());
           }
         }
         else if (qname.equals("product"))
         {
           // sometimes name is returned e.g. for V00488
-          prname = q.getValues()[0];
+          proteinName = q.getValues()[0].trim();
         }
         else
         {
@@ -317,54 +336,62 @@ public class EmblEntry
       }
     }
 
-    DBRefEntry protEMBLCDS = null;
-    exon = MappingUtils.removeStartPositions(codonStart - 1, exon);
-    boolean noProteinDbref = true;
+    DBRefEntry proteinToEmblProteinRef = null;
+    exons = MappingUtils.removeStartPositions(codonStart - 1, exons);
 
     SequenceI product = null;
-    Mapping map = null;
-    if (prseq != null && prname != null && prid != null)
+    Mapping dnaToProteinMapping = null;
+    if (translation != null && proteinName != null && proteinId != null)
     {
+      int translationLength = translation.length();
+
       /*
        * look for product in peptides list, if not found, add it
        */
-      product = matcher.findIdMatch(prid);
+      product = matcher.findIdMatch(proteinId);
       if (product == null)
       {
-        product = new Sequence(prid, prseq, 1, prseq.length());
-        product.setDescription(((prname.length() == 0) ? "Protein Product from "
-                + sourceDb
-                : prname));
+        product = new Sequence(proteinId, translation, 1,
+                translationLength);
+        product.setDescription(((proteinName.length() == 0)
+                ? "Protein Product from " + sourceDb
+                : proteinName));
         peptides.add(product);
         matcher.add(product);
       }
 
       // we have everything - create the mapping and perhaps the protein
       // sequence
-      if (exon == null || exon.length == 0)
+      if (exons == null || exons.length == 0)
       {
-        System.err
-                .println("Implementation Notice: EMBLCDS records not properly supported yet - Making up the CDNA region of this sequence... may be incorrect ("
+        /*
+         * workaround until we handle dna location for CDS sequence
+         * e.g. location="X53828.1:60..1058" correctly
+         */
+        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 - codonStart + dna.getSequence().length))
+        int dnaLength = dna.getLength();
+        if (translationLength * 3 == (1 - codonStart + dnaLength))
         {
-          System.err
-                  .println("Not allowing for additional stop codon at end of cDNA fragment... !");
-          // this might occur for CDS sequences where no features are
-          // marked.
-          exon = new int[] { dna.getStart() + (codonStart - 1),
+          System.err.println(
+                  "Not allowing for additional stop codon at end of cDNA fragment... !");
+          // this might occur for CDS sequences where no features are marked
+          exons = new int[] { dna.getStart() + (codonStart - 1),
               dna.getEnd() };
-          map = new Mapping(product, exon, new int[] { 1, prseq.length() },
-                  3, 1);
+          dnaToProteinMapping = new Mapping(product, exons,
+                  new int[]
+                  { 1, translationLength }, 3, 1);
         }
-        if ((prseq.length() + 1) * 3 == (1 - codonStart + dna.getSequence().length))
+        if ((translationLength + 1) * 3 == (1 - codonStart + dnaLength))
         {
-          System.err
-                  .println("Allowing for additional stop codon at end of cDNA fragment... will probably cause an error in VAMSAs!");
-          exon = new int[] { dna.getStart() + (codonStart - 1),
+          System.err.println(
+                  "Allowing for additional stop codon at end of cDNA fragment... will probably cause an error in VAMSAs!");
+          exons = new int[] { dna.getStart() + (codonStart - 1),
               dna.getEnd() - 3 };
-          map = new Mapping(product, exon, new int[] { 1, prseq.length() },
-                  3, 1);
+          dnaToProteinMapping = new Mapping(product, exons,
+                  new int[]
+                  { 1, translationLength }, 3, 1);
         }
       }
       else
@@ -383,58 +410,98 @@ public class EmblEntry
         else
         {
           // final product length truncation check
-          // TODO should from range include stop codon even if not in protein
-          // in order to include stop codon in CDS sequence (as done for
-          // Ensembl)?
-          int[] cdsRanges = adjustForProteinLength(prseq.length(), exon);
-          map = new Mapping(product, cdsRanges, 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)
-          DBRefEntry pcdnaref = new DBRefEntry();
-          pcdnaref.setAccessionId(prid);
-          pcdnaref.setSource(DBRefSource.EMBLCDS);
-          pcdnaref.setVersion(getSequenceVersion()); // same as parent EMBL
-                                                     // version.
-          MapList mp = new MapList(new int[] { 1, prseq.length() },
-                  new int[] { 1 + (codonStart - 1),
-                      (codonStart - 1) + 3 * prseq.length() }, 1, 3);
-          pcdnaref.setMap(new Mapping(mp));
+          int[] cdsRanges = adjustForProteinLength(translationLength,
+                  exons);
+          dnaToProteinMapping = new Mapping(product, cdsRanges,
+                  new int[]
+                  { 1, translationLength }, 3, 1);
           if (product != null)
           {
-            product.addDBRef(pcdnaref);
-            protEMBLCDS = new DBRefEntry(pcdnaref);
-            protEMBLCDS.setSource(DBRefSource.EMBLCDSProduct);
-            product.addDBRef(protEMBLCDS);
+            /*
+             * make xref with mapping from protein to EMBL dna
+             */
+            DBRefEntry proteinToEmblRef = new DBRefEntry(DBRefSource.EMBL,
+                    getSequenceVersion(), proteinId,
+                    new Mapping(dnaToProteinMapping.getMap().getInverse()));
+            product.addDBRef(proteinToEmblRef);
+
+            /*
+             * make xref from protein to EMBLCDS; we assume here that the 
+             * CDS sequence version is same as dna sequence (?!)
+             */
+            MapList proteinToCdsMapList = new MapList(
+                    new int[]
+                    { 1, translationLength },
+                    new int[]
+                    { 1 + (codonStart - 1),
+                        (codonStart - 1) + 3 * translationLength },
+                    1, 3);
+            DBRefEntry proteinToEmblCdsRef = new DBRefEntry(
+                    DBRefSource.EMBLCDS, getSequenceVersion(), proteinId,
+                    new Mapping(proteinToCdsMapList));
+            product.addDBRef(proteinToEmblCdsRef);
+
+            /*
+             * make 'direct' xref from protein to EMBLCDSPROTEIN
+             */
+            proteinToEmblProteinRef = new DBRefEntry(proteinToEmblCdsRef);
+            proteinToEmblProteinRef.setSource(DBRefSource.EMBLCDSProduct);
+            proteinToEmblProteinRef.setMap(null);
+            product.addDBRef(proteinToEmblProteinRef);
           }
         }
       }
-      // add cds feature to dna seq - this may include the stop codon
-      for (int xint = 0; exon != null && xint < exon.length; xint += 2)
+
+      /*
+       * add cds features to dna sequence
+       */
+      String cds = feature.getName(); // "CDS"
+      for (int xint = 0; exons != null && xint < exons.length - 1; xint += 2)
       {
-        SequenceFeature sf = makeCdsFeature(exon, xint, prname, prid, vals,
-                codonStart);
-        sf.setType(feature.getName()); // "CDS"
+        int exonStart = exons[xint];
+        int exonEnd = exons[xint + 1];
+        int begin = Math.min(exonStart, exonEnd);
+        int end = Math.max(exonStart, exonEnd);
+        int exonNumber = xint / 2 + 1;
+        String desc = String.format("Exon %d for protein '%s' EMBLCDS:%s",
+                exonNumber, proteinName, proteinId);
+
+        SequenceFeature sf = makeCdsFeature(cds, desc, begin, end,
+                sourceDb, vals);
+
         sf.setEnaLocation(feature.getLocation());
-        sf.setFeatureGroup(sourceDb);
+        boolean forwardStrand = exonStart <= exonEnd;
+        sf.setStrand(forwardStrand ? "+" : "-");
+        sf.setPhase(String.valueOf(codonStart - 1));
+        sf.setValue(FeatureProperties.EXONPOS, exonNumber);
+        sf.setValue(FeatureProperties.EXONPRODUCT, proteinName);
+
         dna.addSequenceFeature(sf);
       }
     }
 
     /*
-     * add mappings for Uniprot xrefs
+     * add feature dbRefs to sequence, and mappings for Uniprot xrefs
      */
+    boolean hasUniprotDbref = false;
     if (feature.dbRefs != null)
     {
       boolean mappingUsed = false;
       for (DBRefEntry ref : feature.dbRefs)
       {
-        if (ref.getSource().equals(DBRefSource.UNIPROT))
+        /*
+         * ensure UniProtKB/Swiss-Prot converted to UNIPROT
+         */
+        String source = DBRefUtils.getCanonicalName(ref.getSource());
+        ref.setSource(source);
+        DBRefEntry proteinDbRef = new DBRefEntry(ref.getSource(),
+                ref.getVersion(), ref.getAccessionId());
+        if (source.equals(DBRefSource.UNIPROT))
         {
           String proteinSeqName = DBRefSource.UNIPROT + "|"
                   + ref.getAccessionId();
-          if (map != null && map.getTo() != null)
+          if (dnaToProteinMapping != null
+                  && dnaToProteinMapping.getTo() != null)
           {
             if (mappingUsed)
             {
@@ -442,13 +509,14 @@ public class EmblEntry
                * two or more Uniprot xrefs for the same CDS - 
                * each needs a distinct Mapping (as to a different sequence)
                */
-              map = new Mapping(map);
+              dnaToProteinMapping = new Mapping(dnaToProteinMapping);
             }
             mappingUsed = true;
 
             /*
              * try to locate the protein mapped to (possibly by a 
-             * previous CDS feature)
+             * previous CDS feature); if not found, construct it from
+             * the EMBL translation
              */
             SequenceI proteinSeq = matcher.findIdMatch(proteinSeqName);
             if (proteinSeq == null)
@@ -458,60 +526,63 @@ public class EmblEntry
               matcher.add(proteinSeq);
               peptides.add(proteinSeq);
             }
-            map.setTo(proteinSeq);
-            map.getTo().addDBRef(
-                    new DBRefEntry(ref.getSource(), ref.getVersion(), ref
-                            .getAccessionId()));
-            ref.setMap(map);
+            dnaToProteinMapping.setTo(proteinSeq);
+            dnaToProteinMapping.setMappedFromId(proteinId);
+            proteinSeq.addDBRef(proteinDbRef);
+            ref.setMap(dnaToProteinMapping);
           }
-          noProteinDbref = false;
+          hasUniprotDbref = true;
         }
         if (product != null)
         {
-          DBRefEntry pref = new DBRefEntry(ref.getSource(),
-                  ref.getVersion(), ref.getAccessionId());
+          /*
+           * copy feature dbref to our protein product
+           */
+          DBRefEntry pref = proteinDbRef;
           pref.setMap(null); // reference is direct
           product.addDBRef(pref);
           // Add converse mapping reference
-          if (map != null)
+          if (dnaToProteinMapping != null)
           {
-            Mapping pmap = new Mapping(dna, map.getMap().getInverse());
+            Mapping pmap = new Mapping(dna,
+                    dnaToProteinMapping.getMap().getInverse());
             pref = new DBRefEntry(sourceDb, getSequenceVersion(),
                     this.getAccession());
             pref.setMap(pmap);
-            if (map.getTo() != null)
+            if (dnaToProteinMapping.getTo() != null)
             {
-              map.getTo().addDBRef(pref);
+              dnaToProteinMapping.getTo().addDBRef(pref);
             }
           }
         }
+        dna.addDBRef(ref);
       }
-      if (noProteinDbref && product != null)
+    }
+
+    /*
+     * if we have a product (translation) but no explicit Uniprot dbref
+     * (example: EMBL AAFI02000057 protein_id EAL65544.1)
+     * then construct mappings to an assumed EMBLCDSPROTEIN accession
+     */
+    if (!hasUniprotDbref && product != null)
+    {
+      if (proteinToEmblProteinRef == 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(getSequenceVersion());
-          protEMBLCDS
-                  .setMap(new Mapping(product, map.getMap().getInverse()));
-        }
-        product.addDBRef(protEMBLCDS);
+        // assuming CDSPROTEIN sequence version = dna version (?!)
+        proteinToEmblProteinRef = new DBRefEntry(DBRefSource.EMBLCDSProduct,
+                getSequenceVersion(), proteinId);
+      }
+      product.addDBRef(proteinToEmblProteinRef);
 
-        // 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);
-          }
-        }
+      if (dnaToProteinMapping != null
+              && dnaToProteinMapping.getTo() != null)
+      {
+        DBRefEntry dnaToEmblProteinRef = new DBRefEntry(
+                DBRefSource.EMBLCDSProduct, getSequenceVersion(),
+                proteinId);
+        dnaToEmblProteinRef.setMap(dnaToProteinMapping);
+        dnaToProteinMapping.setMappedFromId(proteinId);
+        dna.addDBRef(dnaToEmblProteinRef);
       }
     }
   }
@@ -519,33 +590,24 @@ public class EmblEntry
   /**
    * Helper method to construct a SequenceFeature for one cds range
    * 
-   * @param exons
-   *          array of cds [start, end, ...] positions
-   * @param exonStartIndex
-   *          offset into the exons array
-   * @param proteinName
-   * @param proteinAccessionId
+   * @param type
+   *          feature type ("CDS")
+   * @param desc
+   *          description
+   * @param begin
+   *          start position
+   * @param end
+   *          end position
+   * @param group
+   *          feature group
    * @param vals
    *          map of 'miscellaneous values' for feature
-   * @param codonStart
-   *          codon start position for CDS (1/2/3, normally 1)
    * @return
    */
-  protected SequenceFeature makeCdsFeature(int[] exons, int exonStartIndex,
-          String proteinName, String proteinAccessionId,
-          Map<String, String> vals, int codonStart)
-  {
-    int exonNumber = exonStartIndex / 2 + 1;
-    SequenceFeature sf = new SequenceFeature();
-    sf.setBegin(Math.min(exons[exonStartIndex], exons[exonStartIndex + 1]));
-    sf.setEnd(Math.max(exons[exonStartIndex], exons[exonStartIndex + 1]));
-    sf.setDescription(String.format("Exon %d for protein '%s' EMBLCDS:%s",
-            exonNumber, proteinName, proteinAccessionId));
-    sf.setPhase(String.valueOf(codonStart - 1));
-    sf.setStrand(exons[exonStartIndex] <= exons[exonStartIndex + 1] ? "+"
-            : "-");
-    sf.setValue(FeatureProperties.EXONPOS, exonNumber);
-    sf.setValue(FeatureProperties.EXONPRODUCT, proteinName);
+  protected SequenceFeature makeCdsFeature(String type, String desc,
+          int begin, int end, String group, Map<String, String> vals)
+  {
+    SequenceFeature sf = new SequenceFeature(type, desc, begin, end, group);
     if (!vals.isEmpty())
     {
       StringBuilder sb = new StringBuilder();
@@ -566,7 +628,7 @@ public class EmblEntry
   }
 
   /**
-   * Returns the CDS positions as a list of [start, end, start, end...]
+   * Returns the CDS positions as a single array of [start, end, start, end...]
    * positions. If on the reverse strand, these will be in descending order.
    * 
    * @param feature
@@ -578,8 +640,18 @@ public class EmblEntry
     {
       return new int[] {};
     }
-    List<int[]> ranges = DnaUtils.parseLocation(feature.location);
-    return ranges == null ? new int[] {} : listToArray(ranges);
+
+    try
+    {
+      List<int[]> ranges = DnaUtils.parseLocation(feature.location);
+      return listToArray(ranges);
+    } catch (ParseException e)
+    {
+      Cache.log.warn(
+              String.format("Not parsing inexact CDS location %s in ENA %s",
+                      feature.location, this.accession));
+      return new int[] {};
+    }
   }
 
   /**
@@ -602,26 +674,30 @@ public class EmblEntry
   }
 
   /**
-   * truncate the last exon interval to the prlength'th codon
+   * Truncates (if necessary) the exon intervals to match 3 times the length of
+   * the protein; also accepts 3 bases longer (for stop codon not included in
+   * protein)
    * 
-   * @param prlength
+   * @param proteinLength
    * @param exon
-   * @return new exon
+   *          an array of [start, end, start, end...] intervals
+   * @return the same array (if unchanged) or a truncated copy
    */
-  static int[] adjustForProteinLength(int prlength, int[] exon)
+  static int[] adjustForProteinLength(int proteinLength, int[] exon)
   {
-    if (prlength <= 0 || exon == null)
+    if (proteinLength <= 0 || exon == null)
     {
       return exon;
     }
-    int desiredCdsLength = prlength * 3;
+    int expectedCdsLength = proteinLength * 3;
     int exonLength = MappingUtils.getLength(Arrays.asList(exon));
 
     /*
-     * assuming here exon might include stop codon in addition to protein codons
+     * if exon length matches protein, or is shorter, or longer by the 
+     * length of a stop codon (3 bases), then leave it unchanged
      */
-    if (desiredCdsLength == exonLength
-            || desiredCdsLength == exonLength - 3)
+    if (expectedCdsLength >= exonLength
+            || expectedCdsLength == exonLength - 3)
     {
       return exon;
     }
@@ -635,11 +711,11 @@ public class EmblEntry
     for (int x = 0; x < exon.length; x += 2)
     {
       cdspos += Math.abs(exon[x + 1] - exon[x]) + 1;
-      if (desiredCdsLength <= cdspos)
+      if (expectedCdsLength <= cdspos)
       {
         // advanced beyond last codon.
         sxpos = x;
-        if (desiredCdsLength != cdspos)
+        if (expectedCdsLength != cdspos)
         {
           // System.err
           // .println("Truncating final exon interval on region by "
@@ -652,11 +728,11 @@ public class EmblEntry
          */
         if (exon[x + 1] >= exon[x])
         {
-          endxon = exon[x + 1] - cdspos + desiredCdsLength;
+          endxon = exon[x + 1] - cdspos + expectedCdsLength;
         }
         else
         {
-          endxon = exon[x + 1] + cdspos - desiredCdsLength;
+          endxon = exon[x + 1] + cdspos - expectedCdsLength;
         }
         break;
       }