JAL-2434 omit unmapped positions from mapping
[jalview.git] / src / jalview / ws / sifts / SiftsClient.java
index 6c94723..30ac0ae 100644 (file)
@@ -29,6 +29,10 @@ import jalview.datamodel.SequenceI;
 import jalview.io.StructureFile;
 import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureMapping;
+import jalview.structure.StructureMappingClient;
+import jalview.structures.models.MappingOutputModel;
+import jalview.util.Comparison;
+import jalview.util.DBRefUtils;
 import jalview.util.Format;
 import jalview.xml.binding.sifts.Entry;
 import jalview.xml.binding.sifts.Entry.Entity;
@@ -51,7 +55,6 @@ import java.nio.file.Path;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -67,14 +70,20 @@ import javax.xml.bind.Unmarshaller;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamReader;
 
-import MCview.Atom;
-import MCview.PDBChain;
-
-public class SiftsClient implements SiftsClientI
+public class SiftsClient extends StructureMappingClient implements
+        SiftsClientI
 {
-  private Entry siftsEntry;
+  /*
+   * for use in mocking out file fetch for tests only
+   * - reset to null after testing!
+   */
+  private static File mockSiftsFile;
+
+  private static final int UNASSIGNED = StructureMapping.UNASSIGNED; // -1
+
+  private static final int PDB_RES_POS = StructureMapping.PDB_RES_NUM_INDEX; // 0
 
-  private StructureFile pdb;
+  private Entry siftsEntry;
 
   private String pdbId;
 
@@ -84,12 +93,6 @@ public class SiftsClient implements SiftsClientI
 
   private static final int BUFFER_SIZE = 4096;
 
-  public static final int UNASSIGNED = -1;
-
-  private static final int PDB_RES_POS = 0;
-
-  private static final int PDB_ATOM_POS = 1;
-
   private static final String NOT_OBSERVED = "Not_Observed";
 
   private static final String SIFTS_FTP_BASE_URL = "http://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/";
@@ -140,15 +143,14 @@ public class SiftsClient implements SiftsClientI
    * @param pdbId
    * @throws SiftsException
    */
-  public SiftsClient(StructureFile pdb) throws SiftsException
+  public SiftsClient(StructureFile structureFile) throws SiftsException
   {
-    this.pdb = pdb;
-    this.pdbId = pdb.getId();
+    this.structureFile = structureFile;
+    this.pdbId = structureFile.getId();
     File siftsFile = getSiftsFile(pdbId);
     siftsEntry = parseSIFTs(siftsFile);
   }
 
-
   /**
    * Parse the given SIFTs File and return a JAXB POJO of parsed data
    * 
@@ -186,6 +188,14 @@ public class SiftsClient implements SiftsClientI
    */
   public static File getSiftsFile(String pdbId) throws SiftsException
   {
+    /*
+     * return mocked file if it has been set
+     */
+    if (mockSiftsFile != null)
+    {
+      return mockSiftsFile;
+    }
+
     String siftsFileName = SiftsSettings.getSiftDownloadDirectory()
             + pdbId.toLowerCase() + ".xml.gz";
     File siftsFile = new File(siftsFileName);
@@ -211,6 +221,10 @@ public class SiftsClient implements SiftsClientI
           return new File(siftsFileName);
         }
       }
+      else
+      {
+        return siftsFile;
+      }
     }
     try
     {
@@ -275,21 +289,23 @@ public class SiftsClient implements SiftsClientI
     {
       siftsDownloadDir.mkdirs();
     }
-      // System.out.println(">> Download ftp url : " + siftsFileFTPURL);
-      URL url = new URL(siftsFileFTPURL);
-      URLConnection conn = url.openConnection();
-      InputStream inputStream = conn.getInputStream();
-      FileOutputStream outputStream = new FileOutputStream(
-              downloadedSiftsFile);
-      byte[] buffer = new byte[BUFFER_SIZE];
-      int bytesRead = -1;
-      while ((bytesRead = inputStream.read(buffer)) != -1)
-      {
-        outputStream.write(buffer, 0, bytesRead);
-      }
-      outputStream.close();
-      inputStream.close();
-      // System.out.println(">>> File downloaded : " + downloadedSiftsFile);
+    // System.out.println(">> Download ftp url : " + siftsFileFTPURL);
+    // long now = System.currentTimeMillis();
+    URL url = new URL(siftsFileFTPURL);
+    URLConnection conn = url.openConnection();
+    InputStream inputStream = conn.getInputStream();
+    FileOutputStream outputStream = new FileOutputStream(
+            downloadedSiftsFile);
+    byte[] buffer = new byte[BUFFER_SIZE];
+    int bytesRead = -1;
+    while ((bytesRead = inputStream.read(buffer)) != -1)
+    {
+      outputStream.write(buffer, 0, bytesRead);
+    }
+    outputStream.close();
+    inputStream.close();
+//    System.out.println(">>> File downloaded : " + downloadedSiftsFile
+//            + " took " + (System.currentTimeMillis() - now) + "ms");
     return new File(downloadedSiftsFile);
   }
 
@@ -323,41 +339,29 @@ public class SiftsClient implements SiftsClientI
   public DBRefEntryI getValidSourceDBRef(SequenceI seq)
           throws SiftsException
   {
-    DBRefEntryI sourceDBRef = null;
-    sourceDBRef = seq.getSourceDBRef();
-    if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef))
+    List<DBRefEntry> dbRefs = seq.getPrimaryDBRefs();
+    if (dbRefs == null || dbRefs.size() < 1)
     {
-      return sourceDBRef;
+      throw new SiftsException(
+              "Source DBRef could not be determined. DBRefs might not have been retrieved.");
     }
-    else
+
+    for (DBRefEntry dbRef : dbRefs)
     {
-      DBRefEntry[] dbRefs = seq.getDBRefs();
-      if (dbRefs == null || dbRefs.length < 1)
+      if (dbRef == null || dbRef.getAccessionId() == null
+              || dbRef.getSource() == null)
       {
-        throw new SiftsException(
-                "Source DBRef could not be determined. DBRefs might not have been retrieved.");
+        continue;
       }
-
-      for (DBRefEntryI dbRef : dbRefs)
+      String canonicalSource = DBRefUtils.getCanonicalName(dbRef
+              .getSource());
+      if (isValidDBRefEntry(dbRef)
+              && (canonicalSource.equalsIgnoreCase(DBRefSource.UNIPROT) || canonicalSource
+                      .equalsIgnoreCase(DBRefSource.PDB)))
       {
-        if (dbRef == null || dbRef.getAccessionId() == null
-                || dbRef.getSource() == null)
-        {
-          continue;
-        }
-        if (isFoundInSiftsEntry(dbRef.getAccessionId())
-                && (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT) || dbRef
-                        .getSource().equalsIgnoreCase(DBRefSource.PDB)))
-        {
-          seq.setSourceDBRef(dbRef);
-          return dbRef;
-        }
+        return dbRef;
       }
     }
-    if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef))
-    {
-      return sourceDBRef;
-    }
     throw new SiftsException("Could not get source DB Ref");
   }
 
@@ -398,12 +402,13 @@ public class SiftsClient implements SiftsClientI
   }
 
   @Override
-  public StructureMapping getSiftsStructureMapping(SequenceI seq,
-          String pdbFile, String chain) throws SiftsException
+  public StructureMapping getStructureMapping(SequenceI seq,
+          String pdbFile, String chain) throws Exception,
+          StructureMappingException
   {
     structId = (chain == null) ? pdbId : pdbId + "|" + chain;
-    System.out.println("Getting mapping for: " + pdbId + "|" + chain
-            + " : seq- " + seq.getName());
+    System.out.println("Getting SIFTS mapping for " + structId + ": seq "
+            + seq.getName());
 
     final StringBuilder mappingDetails = new StringBuilder(128);
     PrintStream ps = new PrintStream(System.out)
@@ -430,7 +435,8 @@ public class SiftsClient implements SiftsClientI
 
   @Override
   public HashMap<Integer, int[]> getGreedyMapping(String entityId,
-          SequenceI seq, java.io.PrintStream os) throws SiftsException
+          SequenceI seq, java.io.PrintStream os) throws SiftsException,
+          StructureMappingException
   {
     List<Integer> omitNonObserved = new ArrayList<Integer>();
     int nonObservedShiftIndex = 0;
@@ -440,7 +446,7 @@ public class SiftsClient implements SiftsClientI
     String originalSeq = AlignSeq.extractGaps(
             jalview.util.Comparison.GapChars, seq.getSequenceAsString());
     HashMap<Integer, int[]> mapping = new HashMap<Integer, int[]>();
-    DBRefEntryI sourceDBRef = seq.getSourceDBRef();
+    DBRefEntryI sourceDBRef;
     sourceDBRef = getValidSourceDBRef(seq);
     // TODO ensure sequence start/end is in the same coordinate system and
     // consistent with the choosen sourceDBRef
@@ -482,12 +488,13 @@ public class SiftsClient implements SiftsClientI
     int pdbStart = UNASSIGNED;
     int pdbEnd = UNASSIGNED;
 
-    Integer[] keys = mapping.keySet().toArray(new Integer[0]);
-    Arrays.sort(keys);
-    if (keys.length < 1)
+    if (mapping.isEmpty())
     {
-      throw new SiftsException(">>> Empty SIFTS mapping generated!!");
+      throw new SiftsException("SIFTS mapping failed");
     }
+
+    Integer[] keys = mapping.keySet().toArray(new Integer[0]);
+    Arrays.sort(keys);
     seqStart = keys[0];
     seqEnd = keys[keys.length - 1];
 
@@ -520,14 +527,14 @@ public class SiftsClient implements SiftsClientI
 
     if (os != null)
     {
-      MappingOutputPojo mop = new MappingOutputPojo();
-      mop.setSeqStart(pdbStart);
-      mop.setSeqEnd(pdbEnd);
+      MappingOutputModel mop = new MappingOutputModel();
+      mop.setSeqStart(seqStart);
+      mop.setSeqEnd(seqEnd);
       mop.setSeqName(seq.getName());
       mop.setSeqResidue(matchedSeq);
 
-      mop.setStrStart(seqStart);
-      mop.setStrEnd(seqEnd);
+      mop.setStrStart(pdbStart);
+      mop.setStrEnd(pdbEnd);
       mop.setStrName(structId);
       mop.setStrResidue(targetStrucSeqs.toString());
 
@@ -622,68 +629,7 @@ public class SiftsClient implements SiftsClientI
       }
     }
   }
-  /**
-   * 
-   * @param chainId
-   *          Target chain to populate mapping of its atom positions.
-   * @param mapping
-   *          Two dimension array of residue index versus atom position
-   * @throws IllegalArgumentException
-   *           Thrown if chainId or mapping is null
-   * @throws SiftsException
-   */
-  void populateAtomPositions(String chainId, Map<Integer, int[]> mapping)
-          throws IllegalArgumentException, SiftsException
-  {
-    try
-    {
-      PDBChain chain = pdb.findChain(chainId);
 
-      if (chain == null || mapping == null)
-      {
-        throw new IllegalArgumentException(
-                "Chain id or mapping must not be null.");
-      }
-      for (int[] map : mapping.values())
-      {
-        if (map[PDB_RES_POS] != UNASSIGNED)
-        {
-          map[PDB_ATOM_POS] = getAtomIndex(map[PDB_RES_POS], chain.atoms);
-        }
-      }
-    } catch (NullPointerException e)
-    {
-      throw new SiftsException(e.getMessage());
-    } catch (Exception e)
-    {
-      throw new SiftsException(e.getMessage());
-    }
-  }
-
-  /**
-   * 
-   * @param residueIndex
-   *          The residue index used for the search
-   * @param atoms
-   *          A collection of Atom to search
-   * @return atom position for the given residue index
-   */
-  int getAtomIndex(int residueIndex, Collection<Atom> atoms)
-  {
-    if (atoms == null)
-    {
-      throw new IllegalArgumentException(
-              "atoms collection must not be null!");
-    }
-    for (Atom atom : atoms)
-    {
-      if (atom.resNumber == residueIndex)
-      {
-        return atom.atomIndex;
-      }
-    }
-    return UNASSIGNED;
-  }
 
   /**
    * Checks if the residue instance is marked 'Not_observed' or not
@@ -773,8 +719,6 @@ public class SiftsClient implements SiftsClientI
     }
   }
 
-
-
   @Override
   public Entity getEntityById(String id) throws SiftsException
   {
@@ -838,6 +782,10 @@ public class SiftsClient implements SiftsClientI
 
     if (sPojo[0].entityId != null)
     {
+      if (sPojo[0].pid < 1)
+      {
+        return null;
+      }
       for (Entity entity : entities)
       {
         if (!entity.getEntityId().equalsIgnoreCase(sPojo[0].entityId))
@@ -944,8 +892,8 @@ public class SiftsClient implements SiftsClientI
   }
 
   @Override
-  public StringBuffer getMappingOutput(MappingOutputPojo mp)
-          throws SiftsException
+  public StringBuffer getMappingOutput(MappingOutputModel mp)
+          throws StructureMappingException
   {
     String seqRes = mp.getSeqResidue();
     String seqName = mp.getSeqName();
@@ -1012,8 +960,10 @@ public class SiftsClient implements SiftsClientI
         {
           if ((i + (j * len)) < seqRes.length())
           {
-            if (seqRes.charAt(i + (j * len)) == strRes
-                    .charAt(i + (j * len))
+            boolean sameChar = Comparison.isSameResidue(
+                    seqRes.charAt(i + (j * len)),
+                    strRes.charAt(i + (j * len)), false);
+            if (sameChar
                     && !jalview.util.Comparison.isGap(seqRes.charAt(i
                             + (j * len))))
             {
@@ -1058,7 +1008,8 @@ public class SiftsClient implements SiftsClientI
     float pid = (float) matchedSeqCount / seqRes.length() * 100;
     if (pid < SiftsSettings.getFailSafePIDThreshold())
     {
-      throw new SiftsException(">>> Low PID detected for SIFTs mapping...");
+      throw new StructureMappingException(
+              ">>> Low PID detected for SIFTs mapping...");
     }
     output.append("Length of alignment = " + seqRes.length()).append(
             NEWLINE);
@@ -1096,4 +1047,9 @@ public class SiftsClient implements SiftsClientI
     return siftsEntry.getDbVersion();
   }
 
+  public static void setMockSiftsFile(File file)
+  {
+    mockSiftsFile = file;
+  }
+
 }