JAL-629 Some refactoring to allow more flexible use of PAE files. Not working as...
[jalview.git] / src / jalview / ws / dbsources / EBIAlfaFold.java
index 672f0ac..aba0d4b 100644 (file)
@@ -27,6 +27,8 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -219,8 +221,8 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
   }
 
   /**
-   * get an alphafold pAE for the given id, and add it to sequence 0 in
-   * pdbAlignment (assuming it came from structurefile parser).
+   * get an alphafold pAE for the given id and return the File object of the
+   * downloaded (temp) file
    * 
    * @param id
    * @param pdbAlignment
@@ -230,8 +232,8 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
    * @throws IOException
    * @throws Exception
    */
-  public static void retrieve_AlphaFold_pAE(String id,
-          AlignmentI pdbAlignment, String retrievalUrl) throws IOException
+  public static File fetchAlphaFoldPAE(String id, String retrievalUrl)
+          throws IOException
   {
     // import PAE as contact matrix - assume this will work if there was a
     // model
@@ -244,7 +246,16 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
               .replace(".cif", ".json");
     }
 
-    File pae = null;
+    // check the cache
+    File pae = paeDownloadCache.get(paeURL);
+    if (pae != null && pae.exists() && (new Date().getTime()
+            - pae.lastModified()) < PAE_CACHE_STALE_TIME)
+    {
+      Console.debug(
+              "Using existing file in PAE cache for '" + paeURL + "'");
+      return pae;
+    }
+
     try
     {
       pae = File.createTempFile(id == null ? "af_pae" : id, "pae_json");
@@ -254,21 +265,35 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
     }
     Console.debug("Downloading pae from " + paeURL + " to " + pae.toString()
             + "");
-    UrlDownloadClient.download(paeURL, pae);
-    addAlphaFoldPAEToSequence(pdbAlignment, pae, 0, null);
-  }
-
-  public static void addAlphaFoldPAEToSequence(AlignmentI pdbAlignment,
-          File pae, int index, String seqId)
-  {
-    addAlphaFoldPAE(pdbAlignment, pae, index, seqId, false, false);
+    try
+    {
+      UrlDownloadClient.download(paeURL, pae);
+    } catch (IOException e)
+    {
+      throw e;
+    }
+    // cache and it if successful
+    paeDownloadCache.put(paeURL, pae);
+    return pae;
   }
 
-  public static void addAlphaFoldPAEToStructure(AlignmentI pdbAlignment,
-          File pae, int index, String structIdOrFile, boolean isStructId)
+  /**
+   * get an alphafold pAE for the given id, and add it to sequence 0 in
+   * pdbAlignment (assuming it came from structurefile parser).
+   * 
+   * @param id
+   * @param pdbAlignment
+   * @param retrievalUrl
+   *          - URL of .mmcif from EBI-AlphaFold - will be used to generate the
+   *          pAE URL automatically
+   * @throws IOException
+   * @throws Exception
+   */
+  public static void retrieve_AlphaFold_pAE(String id,
+          AlignmentI pdbAlignment, String retrievalUrl) throws IOException
   {
-    addAlphaFoldPAE(pdbAlignment, pae, index, structIdOrFile, true,
-            isStructId);
+    File pae = fetchAlphaFoldPAE(id, retrievalUrl);
+    addAlphaFoldPAE(pdbAlignment, pae, 0, null, false, false);
   }
 
   public static void addAlphaFoldPAE(AlignmentI pdbAlignment, File pae,
@@ -291,26 +316,8 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
               .getStructureSelectionManager(Desktop.instance);
       if (ssm != null)
       {
-        String structFile = isStructId ? ssm.findFileForPDBId(id) : id;
-
-        StructureMapping[] smArray = ssm.getMapping(structFile);
-
-        try
-        {
-          if (!importPaeJSONAsContactMatrixToStructure(smArray, paeInput))
-          {
-            Console.warn("Could not import contact matrix from '"
-                    + pae.getAbsolutePath() + "' to structure.");
-          }
-        } catch (IOException e1)
-        {
-          Console.error("Error when importing pAE file '"
-                  + pae.getAbsolutePath() + "'", e1);
-        } catch (ParseException e2)
-        {
-          Console.error("Error when parsing pAE file '"
-                  + pae.getAbsolutePath() + "'", e2);
-        }
+        String structFilename = isStructId ? ssm.findFileForPDBId(id) : id;
+        addPAEToStructure(ssm, structFilename, pae);
       }
 
     }
@@ -338,6 +345,47 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
 
   }
 
+  public static void addPAEToStructure(StructureSelectionManager ssm,
+          String structFilename, File pae)
+  {
+    FileInputStream paeInput = null;
+    try
+    {
+      paeInput = new FileInputStream(pae);
+    } catch (FileNotFoundException e)
+    {
+      Console.error(
+              "Could not find pAE file '" + pae.getAbsolutePath() + "'", e);
+      return;
+    }
+    if (ssm == null)
+    {
+      ssm = StructureSelectionManager
+              .getStructureSelectionManager(Desktop.instance);
+    }
+    if (ssm != null)
+    {
+      StructureMapping[] smArray = ssm.getMapping(structFilename);
+
+      try
+      {
+        if (!importPaeJSONAsContactMatrixToStructure(smArray, paeInput))
+        {
+          Console.warn("Could not import contact matrix from '"
+                  + pae.getAbsolutePath() + "' to structure.");
+        }
+      } catch (IOException e1)
+      {
+        Console.error("Error when importing pAE file '"
+                + pae.getAbsolutePath() + "'", e1);
+      } catch (ParseException e2)
+      {
+        Console.error("Error when parsing pAE file '"
+                + pae.getAbsolutePath() + "'", e2);
+      }
+    }
+  }
+
   /**
    * parses the given pAE matrix and adds it to sequence 0 in the given
    * alignment
@@ -389,7 +437,26 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
         sequence = sequences[0]; // just use the first sequence with this seqId
       }
     }
+    if (sequence == null)
+    {
+      return false;
+    }
+    return importPaeJSONAsContactMatrixToSequence(pdbAlignment, pae_input,
+            sequence);
+  }
+
+  public static boolean importPaeJSONAsContactMatrixToSequence(
+          AlignmentI pdbAlignment, File pae_input, SequenceI sequence)
+          throws IOException, ParseException
+  {
+    return importPaeJSONAsContactMatrixToSequence(pdbAlignment,
+            new FileInputStream(pae_input), sequence);
+  }
 
+  public static boolean importPaeJSONAsContactMatrixToSequence(
+          AlignmentI pdbAlignment, InputStream pae_input,
+          SequenceI sequence) throws IOException, ParseException
+  {
     JSONObject paeDict = parseJSONtoPAEContactMatrix(pae_input);
     if (paeDict == null)
     {
@@ -439,14 +506,6 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
   }
 
   public static boolean importPaeJSONAsContactMatrixToStructure(
-          StructureMapping sm, File paeFile)
-          throws FileNotFoundException, IOException, ParseException
-  {
-    return importPaeJSONAsContactMatrixToStructure(sm,
-            new FileInputStream(paeFile));
-  }
-
-  public static boolean importPaeJSONAsContactMatrixToStructure(
           StructureMapping sm, InputStream paeInput)
           throws IOException, ParseException
   {
@@ -629,4 +688,9 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
     return new PDBFeatureSettings();
   }
 
+  // days * 86400000
+  private static final long PAE_CACHE_STALE_TIME = 1 * 86400000;
+
+  private static Map<String, File> paeDownloadCache = new HashMap<>();
+
 }