JAL-1479 implemented timestamp based caching of SIFTS by providing code which checks...
authortcofoegbu <tcnofoegbu@dundee.ac.uk>
Thu, 7 Jan 2016 14:50:06 +0000 (14:50 +0000)
committertcofoegbu <tcnofoegbu@dundee.ac.uk>
Thu, 7 Jan 2016 14:50:06 +0000 (14:50 +0000)
src/jalview/ws/sifts/SiftsClient.java
test/jalview/ws/sifts/SiftsClientTest.java

index 00da2fc..7d5ae2e 100644 (file)
@@ -47,9 +47,14 @@ import java.io.InputStream;
 import java.io.PrintStream;
 import java.net.URL;
 import java.net.URLConnection;
+import java.nio.file.Files;
+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;
 import java.util.HashSet;
 import java.util.List;
@@ -98,6 +103,8 @@ public class SiftsClient implements SiftsClientI
 
   private final static String NEWLINE = System.lineSeparator();
 
+  private final static int THRESHOLD_IN_DAYS = 2;
+
   private String curSourceDBRef;
 
   private HashSet<String> curDBRefAccessionIdsString;
@@ -180,7 +187,7 @@ public class SiftsClient implements SiftsClientI
     try (InputStream in = new FileInputStream(siftFile);
             GZIPInputStream gzis = new GZIPInputStream(in);)
     {
-      System.out.println("File : " + siftFile.getAbsolutePath());
+      // System.out.println("File : " + siftFile.getAbsolutePath());
       JAXBContext jc = JAXBContext.newInstance("jalview.xml.binding.sifts");
       XMLStreamReader streamReader = XMLInputFactory.newInstance()
               .createXMLStreamReader(gzis);
@@ -220,14 +227,17 @@ public class SiftsClient implements SiftsClientI
   public static File getSiftsFile(String pdbId) throws SiftsException
   {
     File siftsFile = new File(SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase()
-            + ".xml.gz");
+            + pdbId.toLowerCase() + ".xml.gz");
     if (siftsFile.exists())
     {
-      // TODO it may be worth performing an age check to determine if a
-      // new SIFTs file should be re-downloaded as SIFTs entries are usually
-      // updated weekly
+      // The line below is required for unit testing... don't comment it out!!!
       System.out.println(">>> SIFTS File already downloaded for " + pdbId);
+
+      if (isFileOlderThanThreshold(siftsFile, THRESHOLD_IN_DAYS))
+      {
+        // System.out.println("Downloaded file is out of date, hence re-downloading...");
+        siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+      }
       return siftsFile;
     }
     siftsFile = downloadSiftsFile(pdbId.toLowerCase());
@@ -235,6 +245,34 @@ public class SiftsClient implements SiftsClientI
   }
 
   /**
+   * This method enables checking if a cached file has exceeded a certain
+   * threshold(in days)
+   * 
+   * @param file
+   *          the cached file
+   * @param noOfDays
+   *          the threshold in days
+   * @return
+   */
+  public static boolean isFileOlderThanThreshold(File file, int noOfDays)
+  {
+    Path filePath = file.toPath();
+    BasicFileAttributes attr;
+    int diffInDays = 0;
+    try
+    {
+      attr = Files.readAttributes(filePath, BasicFileAttributes.class);
+      diffInDays = (int) ((new Date().getTime() - attr.lastModifiedTime()
+              .toMillis()) / (1000 * 60 * 60 * 24));
+      // System.out.println("Diff in days : " + diffInDays);
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
+    return noOfDays <= diffInDays;
+  }
+
+  /**
    * Download a SIFTs XML file for a given PDB Id from an FTP repository
    * 
    * @param pdbId
@@ -255,7 +293,7 @@ public class SiftsClient implements SiftsClientI
     }
     try
     {
-      System.out.println(">> Download ftp url : " + siftsFileFTPURL);
+      // System.out.println(">> Download ftp url : " + siftsFileFTPURL);
       URL url = new URL(siftsFileFTPURL);
       URLConnection conn = url.openConnection();
       InputStream inputStream = conn.getInputStream();
@@ -269,7 +307,7 @@ public class SiftsClient implements SiftsClientI
       }
       outputStream.close();
       inputStream.close();
-      System.out.println(">>> File downloaded : " + downloadedSiftsFile);
+      // System.out.println(">>> File downloaded : " + downloadedSiftsFile);
     } catch (IOException ex)
     {
       throw new SiftsException(ex.getMessage());
@@ -287,8 +325,7 @@ public class SiftsClient implements SiftsClientI
   public static boolean deleteSiftsFileByPDBId(String pdbId)
   {
     File siftsFile = new File(SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase()
-            + ".xml.gz");
+            + pdbId.toLowerCase() + ".xml.gz");
     if (siftsFile.exists())
     {
       return siftsFile.delete();
@@ -296,7 +333,6 @@ public class SiftsClient implements SiftsClientI
     return true;
   }
 
-
   /**
    * Get a valid SIFTs DBRef for the given sequence current SIFTs entry
    * 
@@ -345,7 +381,6 @@ public class SiftsClient implements SiftsClientI
     throw new SiftsException("Could not get source DB Ref");
   }
 
-
   /**
    * Check that the DBRef Entry is properly populated and is available in this
    * SiftClient instance
@@ -408,15 +443,13 @@ public class SiftsClient implements SiftsClientI
 
     String mappingOutput = mappingDetails.toString();
     StructureMapping siftsMapping = new StructureMapping(seq, pdbFile,
-            pdbId, chain, mapping,
-            mappingOutput);
+            pdbId, chain, mapping, mappingOutput);
     return siftsMapping;
   }
 
   @Override
-  public HashMap<Integer, int[]> getGreedyMapping(String entityId, SequenceI seq,
-          java.io.PrintStream os)
- throws SiftsException
+  public HashMap<Integer, int[]> getGreedyMapping(String entityId,
+          SequenceI seq, java.io.PrintStream os) throws SiftsException
   {
     ArrayList<Integer> omitNonObserved = new ArrayList<Integer>();
     int nonObservedShiftIndex = 0;
@@ -424,8 +457,7 @@ public class SiftsClient implements SiftsClientI
     Entity entity = null;
     entity = getEntityById(entityId);
     String originalSeq = AlignSeq.extractGaps(
-            jalview.util.Comparison.GapChars,
-            seq.getSequenceAsString());
+            jalview.util.Comparison.GapChars, seq.getSequenceAsString());
     HashMap<Integer, int[]> mapping = new HashMap<Integer, int[]>();
     DBRefEntryI sourceDBRef = seq.getSourceDBRef();
     if (sourceDBRef == null)
@@ -477,7 +509,14 @@ public class SiftsClient implements SiftsClientI
             String resNumIndexString = cRefDb.getDbResNum()
                     .equalsIgnoreCase("None") ? String.valueOf(UNASSIGNED)
                     : cRefDb.getDbResNum();
-            currSeqIndex = Integer.valueOf(resNumIndexString);
+            try
+            {
+              currSeqIndex = Integer.valueOf(resNumIndexString);
+            } catch (NumberFormatException nfe)
+            {
+              currSeqIndex = Integer.valueOf(resNumIndexString
+                      .split("[a-zA-Z]")[0]);
+            }
             if (pdbRefDb != null)
             {
               break;// exit loop if pdb and uniprot are already found
@@ -494,7 +533,8 @@ public class SiftsClient implements SiftsClientI
           try
           {
             resNum = (pdbRefDb == null) ? Integer.valueOf(residue
-                  .getDbResNum()) : Integer.valueOf(pdbRefDb.getDbResNum());
+                    .getDbResNum()) : Integer.valueOf(pdbRefDb
+                    .getDbResNum());
           } catch (NumberFormatException nfe)
           {
             resNum = (pdbRefDb == null) ? Integer.valueOf(residue
@@ -526,7 +566,10 @@ public class SiftsClient implements SiftsClientI
     {
       e.printStackTrace();
     }
-    padWithGaps(resNumMap, omitNonObserved);
+    if (seqCoordSys == CoordinateSys.UNIPROT)
+    {
+      padWithGaps(resNumMap, omitNonObserved);
+    }
     int seqStart = UNASSIGNED;
     int seqEnd = UNASSIGNED;
     int pdbStart = UNASSIGNED;
@@ -662,7 +705,6 @@ public class SiftsClient implements SiftsClientI
     }
   }
 
-
   /**
    * 
    * @param chainId
@@ -727,9 +769,94 @@ public class SiftsClient implements SiftsClientI
       }
       return entity;
     }
+    Entity entity = getEntityByMostOptimalMatchedId(id);
+    if (entity != null)
+    {
+      return entity;
+    }
     throw new SiftsException("Entity " + id + " not found");
   }
 
+  /**
+   * This method was added because EntityId is NOT always equal to ChainId.
+   * Hence, it provides the logic to greedily detect the "true" Entity for a
+   * given chainId where discrepancies exist.
+   * 
+   * @param chainId
+   * @return
+   */
+  public Entity getEntityByMostOptimalMatchedId(String chainId)
+  {
+    System.out
+            .println("--------------> advanced greedy entityId matching block entered..");
+    List<Entity> entities = siftsEntry.getEntity();
+    SiftsEntitySortPojo[] sPojo = new SiftsEntitySortPojo[entities.size()];
+    int count = 0;
+    for (Entity entity : entities)
+    {
+      sPojo[count] = new SiftsEntitySortPojo();
+      sPojo[count].entityId = entity.getEntityId();
+
+      List<Segment> segments = entity.getSegment();
+      for (Segment segment : segments)
+      {
+        List<Residue> residues = segment.getListResidue().getResidue();
+        for (Residue residue : residues)
+        {
+          List<CrossRefDb> cRefDbs = residue.getCrossRefDb();
+          for (CrossRefDb cRefDb : cRefDbs)
+          {
+            if (!cRefDb.getDbSource().equalsIgnoreCase("PDB"))
+            {
+              continue;
+            }
+            ++sPojo[count].resCount;
+            if (cRefDb.getDbChainId().equalsIgnoreCase(chainId))
+            {
+              ++sPojo[count].chainIdFreq;
+            }
+          }
+        }
+      }
+      sPojo[count].pid = 100 * (sPojo[count].chainIdFreq / sPojo[count].resCount);
+      ++count;
+    }
+    Arrays.sort(sPojo, Collections.reverseOrder());
+    System.out.println("highest matched entity : " + sPojo[0].entityId);
+    System.out.println("highest matched pid : " + sPojo[0].pid);
+
+    if (sPojo[0].entityId != null)
+    {
+      for (Entity entity : entities)
+      {
+        if (!entity.getEntityId().equalsIgnoreCase(sPojo[0].entityId))
+        {
+          continue;
+        }
+        return entity;
+      }
+    }
+    return null;
+  }
+
+  public class SiftsEntitySortPojo implements
+          Comparable<SiftsEntitySortPojo>
+  {
+    public String entityId;
+
+    public int chainIdFreq;
+
+    public int pid;
+
+    public int resCount;
+
+    @Override
+    public int compareTo(SiftsEntitySortPojo o)
+    {
+      return this.pid - o.pid;
+    }
+  }
+
   @Override
   public String[] getEntryDBs()
   {
@@ -757,9 +884,9 @@ public class SiftsClient implements SiftsClientI
     String strName = mp.getStrName();
     int pdbStart = mp.getStrStart();
     int pdbEnd = mp.getStrEnd();
-    
+
     String type = mp.getType();
-    
+
     int maxid = (seqName.length() >= strName.length()) ? seqName.length()
             : strName.length();
     int len = 72 - maxid - 1;
@@ -786,7 +913,7 @@ public class SiftsClient implements SiftsClientI
     output.append(" - ");
     output.append(String.valueOf(pdbEnd));
     output.append(NEWLINE).append(NEWLINE);
-    
+
     int matchedSeqCount = 0;
     for (int j = 0; j < nochunks; j++)
     {
@@ -810,32 +937,33 @@ public class SiftsClient implements SiftsClientI
       {
         try
         {
-        if ((i + (j * len)) < seqRes.length())
-        {
-          if (seqRes.charAt(i + (j * len)) == strRes.charAt(i + (j * len))
-                  && !jalview.util.Comparison.isGap(seqRes.charAt(i
-                          + (j * len))))
+          if ((i + (j * len)) < seqRes.length())
           {
+            if (seqRes.charAt(i + (j * len)) == strRes
+                    .charAt(i + (j * len))
+                    && !jalview.util.Comparison.isGap(seqRes.charAt(i
+                            + (j * len))))
+            {
               matchedSeqCount++;
-            output.append("|");
-          }
-          else if (type.equals("pep"))
-          {
-            if (ResidueProperties.getPAM250(seqRes.charAt(i + (j * len)),
-                    strRes.charAt(i + (j * len))) > 0)
+              output.append("|");
+            }
+            else if (type.equals("pep"))
             {
-              output.append(".");
+              if (ResidueProperties.getPAM250(seqRes.charAt(i + (j * len)),
+                      strRes.charAt(i + (j * len))) > 0)
+              {
+                output.append(".");
+              }
+              else
+              {
+                output.append(" ");
+              }
             }
             else
             {
               output.append(" ");
             }
           }
-          else
-          {
-            output.append(" ");
-          }
-        }
         } catch (IndexOutOfBoundsException e)
         {
           continue;
@@ -859,13 +987,13 @@ public class SiftsClient implements SiftsClientI
     {
       throw new SiftsException("Low PID detected for SIFTs mapping...");
     }
-    output.append("Length of alignment = " + seqRes.length())
-            .append(NEWLINE);
+    output.append("Length of alignment = " + seqRes.length()).append(
+            NEWLINE);
     output.append(new Format("Percentage ID = %2.2f").form(pid));
     output.append(NEWLINE);
     return output;
   }
-  
+
   @Override
   public int getEntityCount()
   {
@@ -901,4 +1029,5 @@ public class SiftsClient implements SiftsClientI
   {
     return siftsEntry.getDbVersion();
   }
+
 }
index 24c6751..28b44e1 100644 (file)
@@ -41,6 +41,11 @@ public class SiftsClientTest
 {
   private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
 
+  public static final String DEFAULT_SIFTS_DOWNLOAD_DIR = System
+          .getProperty("user.home")
+          + File.separatorChar
+          + ".sifts_downloads" + File.separatorChar;
+
   private String testPDBId = "1a70";
 
   private SiftsClient siftsClient = null;
@@ -69,9 +74,13 @@ public class SiftsClientTest
   {
     // SIFTs entries are updated weekly - so use saved SIFTs file to enforce
     // test reproducibility
+    SiftsSettings.setSiftDownloadDirectory(jalview.bin.Cache.getDefault(
+            "sifts_download_dir", DEFAULT_SIFTS_DOWNLOAD_DIR));
+
     File testSiftsFile = new File("test/jalview/io/" + testPDBId
             + ".xml.gz");
     PDBfile pdbFile = new PDBfile(false, false, false);
+    pdbFile.id = testPDBId;
     siftsClient = new SiftsClient(pdbFile, testSiftsFile);
   }