JAL-1803 first pass at updatePDBEntry
authorJim Procter <jprocter@issues.jalview.org>
Wed, 7 Sep 2016 10:54:14 +0000 (11:54 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Wed, 7 Sep 2016 10:54:14 +0000 (11:54 +0100)
* merge PDBEntry if same ID, existing is null or identical filename, and chaincode is unspecified or identical to new one.
* merge propagates type, chainCode, filename, and all properties to parent.

Note TODOs: we don’t recognise and merge 1QIPA onto 1QIP (yet)

src/jalview/datamodel/PDBEntry.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceI.java

index 673c12a..1c1d192 100755 (executable)
@@ -245,4 +245,54 @@ public class PDBEntry
   {
     return id;
   }
+
+  /**
+   * update entry with details from another entry concerning the same PDB
+   * ID/file spec.
+   * 
+   * @param newEntry
+   * @return true if modifications were made
+   */
+  public boolean updateFrom(PDBEntry newEntry)
+  {
+    boolean modified = false;
+
+    if (getFile() == null)
+    {
+      // update file and type of file
+      modified |= newEntry.getFile() != null;
+      setFile(newEntry.getFile());
+    }
+    if (newEntry.getType() != null && newEntry.getFile() != null
+            && newEntry.getFile().equals(getFile()))
+    {
+      setType(newEntry.getType());
+    }
+    if (getChainCode() == null
+            || (getChainCode() != null && getChainCode().length() == 0 && newEntry
+                    .getChainCode() != null))
+    {
+      modified |= getChainCode() == null
+              || !newEntry.getChainCode().equals(getChainCode());
+      setChainCode(newEntry.getChainCode());
+    }
+    if (newEntry.getProperty() != null)
+    {
+      if (properties == null)
+      {
+        properties = new Hashtable();
+      }
+      // TODO: getProperty -> Map<String,String>
+      for (Object p : newEntry.getProperty().keySet())
+      {
+        if (properties.get(p) == null
+                || !properties.get(p).equals(newEntry.getProperty().get(p)))
+        {
+          modified = true;
+        }
+        properties.put(p, newEntry.getProperty().get(p));
+      }
+    }
+    return modified;
+  }
 }
index 5886ae0..4f626a4 100755 (executable)
@@ -418,22 +418,66 @@ public class Sequence extends ASequence implements SequenceI
     {
       pdbIds = new Vector<PDBEntry>();
     }
-    if (pdbIds.contains(entry))
-    {
-      updatePDBEntry(pdbIds.get(pdbIds.indexOf(entry)), entry);
-    }
-    else
+    if (!updatedPDBEntry(pdbIds, entry))
     {
       pdbIds.addElement(entry);
     }
   }
 
-  private static void updatePDBEntry(PDBEntry oldEntry, PDBEntry newEntry)
+  private static boolean updatedPDBEntry(List<PDBEntry> entries,
+          PDBEntry newEntry)
   {
-    if (newEntry.getFile() != null)
+    for (PDBEntry xtant : entries)
     {
-      oldEntry.setFile(newEntry.getFile());
+      if (xtant.getFile() != null && newEntry.getFile() != null
+              && !xtant.getFile().equals(newEntry.getFile()))
+      {
+        // different structure data, so leave alone.
+        continue;
+      }
+      // loop through to check whether we can find a matching ID
+
+      // either exact
+      if (!xtant.getId().equals(newEntry.getId()))
+      {
+        /* TODO: support stemming to group PDB IDs.
+        // or stemming, with exactly one alphanumeric character difference
+        if (xtant.getId().length() < newEntry.getId().length())
+        {
+          if (!newEntry.getId().startsWith(xtant.getId()))
+          {
+            continue;
+          }
+          // newEntry may be chain specific PDBEntry
+          // TODO: copy/update details from newEntry to xtant
+        }
+        else
+        {
+          if (!xtant.getId().startsWith(newEntry.getId()))
+          {
+            continue;
+          }
+          // xtant may be chain specific PDBEntry
+          // TODO: copy/update missing details from newEntry
+        }*/
+        continue;
+      }
+      if (xtant.getChainCode() != null && xtant.getChainCode().length() > 0
+              && newEntry.getChainCode() != null
+              && !newEntry.getChainCode().equals(xtant.getChainCode()))
+      {
+        // don't overwrite - multiple chain mappings for a sequence yield
+        // multiple PDBEntries
+        // each with different chaincode
+        continue;
+      }
+
+      xtant.updateFrom(newEntry);
+
+      return true;
     }
+    // if we got to the end of the loop, nothing was updated.
+    return false;
   }
 
   /**
index ec7520b..55c59db 100755 (executable)
@@ -289,7 +289,12 @@ public interface SequenceI extends ASequenceI
   public Vector<PDBEntry> getAllPDBEntries();
 
   /**
-   * add entry to the vector of PDBIds, if it isn't in the list already
+   * add entry to the *normalised* vector of PDBIds.
+   * 
+   * If a PDBEntry is passed with an entry.getID() string, as one already in the
+   * list, or one is added that appears to be the same but has a chain ID
+   * appended, then the existing PDBEntry will be updated with the new
+   * attributes.
    * 
    * @param entry
    */