Merge branch 'develop' into update_212_Dec_merge_with_21125_chamges
[jalview.git] / src / jalview / ws / sifts / SiftsClient.java
index 9790f79..892ebd8 100644 (file)
@@ -39,18 +39,18 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.zip.GZIPInputStream;
 
 import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
 import javax.xml.bind.Unmarshaller;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamReader;
 
-import MCview.Atom;
-import MCview.PDBChain;
 import jalview.analysis.AlignSeq;
 import jalview.analysis.scoremodels.ScoreMatrix;
 import jalview.analysis.scoremodels.ScoreModels;
@@ -66,6 +66,7 @@ import jalview.structure.StructureMapping;
 import jalview.util.Comparison;
 import jalview.util.DBRefUtils;
 import jalview.util.Format;
+import jalview.util.Platform;
 import jalview.xml.binding.sifts.Entry;
 import jalview.xml.binding.sifts.Entry.Entity;
 import jalview.xml.binding.sifts.Entry.Entity.Segment;
@@ -73,6 +74,8 @@ import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.ResidueDetail;
+import mc_view.Atom;
+import mc_view.PDBChain;
 
 public class SiftsClient implements SiftsClientI
 {
@@ -116,14 +119,16 @@ public class SiftsClient implements SiftsClientI
 
   private final static String NEWLINE = System.lineSeparator();
 
+  private static final boolean GET_STREAM = false;
+  private static final boolean CACHE_FILE = true;
   private String curSourceDBRef;
 
   private HashSet<String> curDBRefAccessionIdsString;
+  private boolean doCache = false;
 
   private enum CoordinateSys
   {
     UNIPROT("UniProt"), PDB("PDBresnum"), PDBe("PDBe");
-
     private String name;
 
     private CoordinateSys(String name)
@@ -141,7 +146,6 @@ public class SiftsClient implements SiftsClientI
   {
     NAME_SEC_STRUCTURE("nameSecondaryStructure"),
     CODE_SEC_STRUCTURE("codeSecondaryStructure"), ANNOTATION("Annotation");
-
     private String code;
 
     private ResidueDetailType(String code)
@@ -166,8 +170,31 @@ public class SiftsClient implements SiftsClientI
   {
     this.pdb = pdb;
     this.pdbId = pdb.getId();
-    File siftsFile = getSiftsFile(pdbId);
-    siftsEntry = parseSIFTs(siftsFile);
+    if (doCache) {
+      File siftsFile = getSiftsFile(pdbId);
+      siftsEntry = parseSIFTs(siftsFile);
+    } else {
+      siftsEntry = parseSIFTSStreamFor(pdbId);
+    }
+  }
+
+  /**
+   * A more streamlined version of SIFT reading that allows for streaming of the data.
+   * 
+   * @param pdbId
+   * @return
+   * @throws SiftsException
+   */
+  private static Entry parseSIFTSStreamFor(String pdbId) throws SiftsException
+  {
+    try
+    {
+      InputStream is = (InputStream) downloadSifts(pdbId, GET_STREAM);
+      return parseSIFTs(is);
+    } catch (Exception e)
+    {
+      throw new SiftsException(e.getMessage());
+    }
   }
 
   /**
@@ -181,19 +208,25 @@ public class SiftsClient implements SiftsClientI
    */
   private Entry parseSIFTs(File siftFile) throws SiftsException
   {
-    try (InputStream in = new FileInputStream(siftFile);
-            GZIPInputStream gzis = new GZIPInputStream(in);)
+    try (InputStream in = new FileInputStream(siftFile)) {
+      return parseSIFTs(in);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      throw new SiftsException(e.getMessage());
+    }
+  }
+  
+  private static Entry parseSIFTs(InputStream in) throws Exception {
+    try (GZIPInputStream gzis = new GZIPInputStream(in);)
     {
       // System.out.println("File : " + siftFile.getAbsolutePath());
       JAXBContext jc = JAXBContext.newInstance("jalview.xml.binding.sifts");
       XMLStreamReader streamReader = XMLInputFactory.newInstance()
               .createXMLStreamReader(gzis);
       Unmarshaller um = jc.createUnmarshaller();
-      return (Entry) um.unmarshal(streamReader);
-    } catch (Exception e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
+      JAXBElement<Entry> jbe = um.unmarshal(streamReader, Entry.class);
+      return jbe.getValue();
     }
   }
 
@@ -216,21 +249,21 @@ public class SiftsClient implements SiftsClientI
     }
 
     String siftsFileName = SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase() + ".xml.gz";
+            + pdbId.toLowerCase(Locale.ROOT) + ".xml.gz";
     File siftsFile = new File(siftsFileName);
     if (siftsFile.exists())
     {
       // 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,
+      if (Platform.isFileOlderThanThreshold(siftsFile,
               SiftsSettings.getCacheThresholdInDays()))
       {
         File oldSiftsFile = new File(siftsFileName + "_old");
         BackupFiles.moveFileToFile(siftsFile, oldSiftsFile);
         try
         {
-          siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+          siftsFile = downloadSiftsFile(pdbId.toLowerCase(Locale.ROOT));
           oldSiftsFile.delete();
           return siftsFile;
         } catch (IOException e)
@@ -247,7 +280,7 @@ public class SiftsClient implements SiftsClientI
     }
     try
     {
-      siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+      siftsFile = downloadSiftsFile(pdbId.toLowerCase(Locale.ROOT));
     } catch (IOException e)
     {
       throw new SiftsException(e.getMessage());
@@ -256,35 +289,6 @@ 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
@@ -294,39 +298,48 @@ public class SiftsClient implements SiftsClientI
    */
   public static File downloadSiftsFile(String pdbId)
           throws SiftsException, IOException
+  {    
+    return (File) downloadSifts(pdbId, CACHE_FILE);
+  }
+
+  /**
+   * Download SIFTs XML with the option to cache a file or to get a stream.
+   * 
+   * @param pdbId
+   * @param asFile 
+   * @return
+   * @throws IOException
+   */
+  private static Object downloadSifts(String pdbId, boolean asFile) throws IOException
   {
+    pdbId = pdbId.toLowerCase(Locale.ROOT);
     if (pdbId.contains(".cif"))
     {
       pdbId = pdbId.replace(".cif", "");
     }
     String siftFile = pdbId + ".xml.gz";
-    String siftsFileFTPURL = SIFTS_FTP_BASE_URL + siftFile;
-    String downloadedSiftsFile = SiftsSettings.getSiftDownloadDirectory()
-            + siftFile;
-    File siftsDownloadDir = new File(
-            SiftsSettings.getSiftDownloadDirectory());
-    if (!siftsDownloadDir.exists())
+    File downloadTo = null;
+    if (asFile)
     {
-      siftsDownloadDir.mkdirs();
+      downloadTo = new File(
+              SiftsSettings.getSiftDownloadDirectory() + siftFile);
+      File siftsDownloadDir = new File(SiftsSettings.getSiftDownloadDirectory());
+      if (!siftsDownloadDir.exists())
+      {
+        siftsDownloadDir.mkdirs();
+      }
     }
-    // System.out.println(">> Download ftp url : " + siftsFileFTPURL);
-    // long now = System.currentTimeMillis();
+
+    String siftsFileFTPURL = SIFTS_FTP_BASE_URL + siftFile;
     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);
+    InputStream is = conn.getInputStream();
+    if (!asFile)
+      return is;
+    // This is MUCH more efficent in JavaScript, as we already have the bytes
+    Platform.streamToFile(is, downloadTo);
+    is.close();
+    return downloadTo;
   }
 
   /**
@@ -339,7 +352,7 @@ public class SiftsClient implements SiftsClientI
   public static boolean deleteSiftsFileByPDBId(String pdbId)
   {
     File siftsFile = new File(SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase() + ".xml.gz");
+            + pdbId.toLowerCase(Locale.ROOT) + ".xml.gz");
     if (siftsFile.exists())
     {
       return siftsFile.delete();
@@ -413,8 +426,8 @@ public class SiftsClient implements SiftsClientI
                 .getMapRegion();
         for (MapRegion mapRegion : mapRegions)
         {
-          accessions
-                  .add(mapRegion.getDb().getDbAccessionId().toLowerCase());
+          accessions.add(mapRegion.getDb().getDbAccessionId()
+                  .toLowerCase(Locale.ROOT));
         }
       }
     }
@@ -463,7 +476,7 @@ public class SiftsClient implements SiftsClientI
           SequenceI seq, java.io.PrintStream os) throws SiftsException
   {
     List<Integer> omitNonObserved = new ArrayList<>();
-    int nonObservedShiftIndex = 0, pdbeNonObserved = 0;
+    int nonObservedShiftIndex = 0,pdbeNonObserved=0;
     // System.out.println("Generating mappings for : " + entityId);
     Entity entity = null;
     entity = getEntityById(entityId);
@@ -484,9 +497,11 @@ public class SiftsClient implements SiftsClientI
     HashSet<String> dbRefAccessionIdsString = new HashSet<String>();
     for (DBRefEntry dbref : seq.getDBRefs())
     {
-      dbRefAccessionIdsString.add(dbref.getAccessionId().toLowerCase());
+      dbRefAccessionIdsString
+              .add(dbref.getAccessionId().toLowerCase(Locale.ROOT));
     }
-    dbRefAccessionIdsString.add(sourceDBRef.getAccessionId().toLowerCase());
+    dbRefAccessionIdsString
+            .add(sourceDBRef.getAccessionId().toLowerCase(Locale.ROOT));
 
     curDBRefAccessionIdsString = dbRefAccessionIdsString;
     curSourceDBRef = sourceDBRef.getAccessionId();
@@ -494,7 +509,7 @@ public class SiftsClient implements SiftsClientI
     TreeMap<Integer, String> resNumMap = new TreeMap<Integer, String>();
     List<Segment> segments = entity.getSegment();
     SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap,
-            omitNonObserved, nonObservedShiftIndex, pdbeNonObserved);
+            omitNonObserved, nonObservedShiftIndex,pdbeNonObserved);
     processSegments(segments, shp);
     try
     {
@@ -516,20 +531,18 @@ public class SiftsClient implements SiftsClientI
     {
       throw new SiftsException("SIFTS mapping failed");
     }
-    // also construct a mapping object between the seq-coord sys and the PDB
-    // seq's coord sys
+    // also construct a mapping object between the seq-coord sys and the PDB seq's coord sys
 
     Integer[] keys = mapping.keySet().toArray(new Integer[0]);
     Arrays.sort(keys);
     seqStart = keys[0];
     seqEnd = keys[keys.length - 1];
-    List<int[]> from = new ArrayList<>(), to = new ArrayList<>();
-    int[] _cfrom = null, _cto = null;
+    List<int[]> from=new ArrayList<>(),to=new ArrayList<>();
+    int[]_cfrom=null,_cto=null;
     String matchedSeq = originalSeq;
-    if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb
-                                // sequence that starts <-1
+    if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb sequence that starts <-1
     {
-      for (int seqps : keys)
+      for (int seqps:keys)
       {
         int pdbpos = mapping.get(seqps)[PDBE_POS];
         if (pdbpos == UNASSIGNED)
@@ -537,23 +550,19 @@ public class SiftsClient implements SiftsClientI
           // not correct - pdbpos might be -1, but leave it for now
           continue;
         }
-        if (_cfrom == null || seqps != _cfrom[1] + 1)
+        if (_cfrom==null || seqps!=_cfrom[1]+1)
         {
-          _cfrom = new int[] { seqps, seqps };
+          _cfrom = new int[] { seqps,seqps};
           from.add(_cfrom);
           _cto = null; // discontinuity
+        } else {
+          _cfrom[1]= seqps;
         }
-        else
+        if (_cto==null || pdbpos!=1+_cto[1])
         {
-          _cfrom[1] = seqps;
-        }
-        if (_cto == null || pdbpos != 1 + _cto[1])
-        {
-          _cto = new int[] { pdbpos, pdbpos };
+          _cto = new int[] { pdbpos,pdbpos};
           to.add(_cto);
-        }
-        else
-        {
+        } else {
           _cto[1] = pdbpos;
         }
       }
@@ -575,7 +584,8 @@ public class SiftsClient implements SiftsClientI
       ;
 
       seqFromPdbMapping = new jalview.datamodel.Mapping(null, _cto, _cfrom,
-              1, 1);
+              1,
+              1);
       pdbStart = mapping.get(seqStart)[PDB_RES_POS];
       pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
       int orignalSeqStart = seq.getStart();
@@ -638,7 +648,7 @@ public class SiftsClient implements SiftsClientI
       for (Residue residue : residues)
       {
         boolean isObserved = isResidueObserved(residue);
-        int pdbeIndex = getLeadingIntegerValue(residue.getDbResNum(),
+        int pdbeIndex = Platform.getLeadingIntegerValue(residue.getDbResNum(),
                 UNASSIGNED);
         int currSeqIndex = UNASSIGNED;
         List<CrossRefDb> cRefDbs = residue.getCrossRefDb();
@@ -650,7 +660,7 @@ public class SiftsClient implements SiftsClientI
             pdbRefDb = cRefDb;
             if (firstPDBResNum == UNASSIGNED)
             {
-              firstPDBResNum = getLeadingIntegerValue(cRefDb.getDbResNum(),
+              firstPDBResNum = Platform.getLeadingIntegerValue(cRefDb.getDbResNum(),
                       UNASSIGNED);
             }
             else
@@ -665,7 +675,7 @@ public class SiftsClient implements SiftsClientI
           if (cRefDb.getDbCoordSys().equalsIgnoreCase(seqCoordSys.getName())
                   && isAccessionMatched(cRefDb.getDbAccessionId()))
           {
-            currSeqIndex = getLeadingIntegerValue(cRefDb.getDbResNum(),
+            currSeqIndex = Platform.getLeadingIntegerValue(cRefDb.getDbResNum(),
                     UNASSIGNED);
             if (pdbRefDb != null)
             {
@@ -706,18 +716,18 @@ public class SiftsClient implements SiftsClientI
         }
         // if (currSeqIndex >= seq.getStart() && currSeqIndex <= seqlength) //
         // true
-        // numbering
-        // is
-        // not
-        // up
-        // to
-        // seq.getEnd()
+                                                                         // numbering
+                                                                         // is
+                                                                         // not
+                                                                         // up
+                                                                         // to
+                                                                         // seq.getEnd()
         {
 
           int resNum = (pdbRefDb == null)
-                  ? getLeadingIntegerValue(residue.getDbResNum(),
+                  ? Platform.getLeadingIntegerValue(residue.getDbResNum(),
                           UNASSIGNED)
-                  : getLeadingIntegerValue(pdbRefDb.getDbResNum(),
+                  : Platform.getLeadingIntegerValue(pdbRefDb.getDbResNum(),
                           UNASSIGNED);
 
           if (isObserved)
@@ -738,29 +748,6 @@ public class SiftsClient implements SiftsClientI
   }
 
   /**
-   * Get the leading integer part of a string that begins with an integer.
-   * 
-   * @param input
-   *          - the string input to process
-   * @param failValue
-   *          - value returned if unsuccessful
-   * @return
-   */
-  static int getLeadingIntegerValue(String input, int failValue)
-  {
-    if (input == null)
-    {
-      return failValue;
-    }
-    String[] parts = input.split("(?=\\D)(?<=\\d)");
-    if (parts != null && parts.length > 0 && parts[0].matches("[0-9]+"))
-    {
-      return Integer.valueOf(parts[0]);
-    }
-    return failValue;
-  }
-
-  /**
    * 
    * @param chainId
    *          Target chain to populate mapping of its atom positions.
@@ -874,14 +861,15 @@ public class SiftsClient implements SiftsClientI
   {
     boolean isStrictMatch = true;
     return isStrictMatch ? curSourceDBRef.equalsIgnoreCase(accession)
-            : curDBRefAccessionIdsString.contains(accession.toLowerCase());
+            : curDBRefAccessionIdsString
+                    .contains(accession.toLowerCase(Locale.ROOT));
   }
 
   private boolean isFoundInSiftsEntry(String accessionId)
   {
     Set<String> siftsDBRefs = getAllMappingAccession();
     return accessionId != null
-            && siftsDBRefs.contains(accessionId.toLowerCase());
+            && siftsDBRefs.contains(accessionId.toLowerCase(Locale.ROOT));
   }
 
   /**
@@ -1051,7 +1039,6 @@ public class SiftsClient implements SiftsClientI
     {
       return pdbeNonObserved;
     }
-
     public SequenceI getSeq()
     {
       return seq;