Merge branch 'feature/JAL-3855_ebi_alphafold_import' (commit '7856e91f60adc5c2d4943ba...
authorJim Procter <j.procter@dundee.ac.uk>
Thu, 26 Aug 2021 13:57:47 +0000 (14:57 +0100)
committerJim Procter <j.procter@dundee.ac.uk>
Mon, 30 Aug 2021 11:17:32 +0000 (12:17 +0100)
23 files changed:
resources/fts/pdb_data_columns.txt
resources/fts/tdbeacons_data_columns.txt [new file with mode: 0644]
src/jalview/datamodel/PDBEntry.java
src/jalview/fts/api/FTSRestClientI.java
src/jalview/fts/core/FTSDataColumnPreferences.java
src/jalview/fts/core/FTSRestClient.java
src/jalview/fts/core/FTSRestResponse.java
src/jalview/fts/service/pdb/PDBFTSRestClient.java
src/jalview/fts/service/threedbeacons/.gitignore [new file with mode: 0644]
src/jalview/fts/service/threedbeacons/TDBeaconsFTSPanel.java [new file with mode: 0644]
src/jalview/fts/service/threedbeacons/TDBeaconsFTSRestClient.java [new file with mode: 0644]
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/structurechooser/StructureChooserQuerySource.java [new file with mode: 0644]
src/jalview/jbgui/GStructureChooser.java
src/jalview/ws/SequenceFetcher.java
src/jalview/ws/dbsources/TDBeacons.java [new file with mode: 0644]
test/jalview/fts/service/pdb/PDBFTSPanelTest.java
test/jalview/fts/service/pdb/PDBFTSRestClientTest.java
test/jalview/fts/threedbeacons/.gitignore [new file with mode: 0644]
test/jalview/fts/threedbeacons/TDBeaconsFTSRestClientTest.java [new file with mode: 0644]
test/jalview/fts/threedbeacons/TDBeaconsPanelTest.java [new file with mode: 0644]
test/jalview/gui/StructureChooserTest.java

index 278b86e..38f0853 100644 (file)
@@ -75,7 +75,6 @@ Space Group;spacegroup;String;g6;50;400;95;false;false
 Cath Code;cath_code;String;g2;50;400;95;false;false
 Tax Id;tax_id;String;g2;50;400;95;false;false
 Tax Query;tax_query;String;g2;50;400;95;false;false
-Interacting Entity Id;interacting_entity_id;String;g2;50;400;95;false;false
 Interacting Molecules;interacting_molecules;String;g6;50;400;95;false;false
 Pubmed Id;pubmed_id;int;g2;50;400;95;false;false
 Status;status;String;g6;50;400;95;false;false
diff --git a/resources/fts/tdbeacons_data_columns.txt b/resources/fts/tdbeacons_data_columns.txt
new file mode 100644 (file)
index 0000000..5cd9f0d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+tdbeacons_data_columns
+#
+_group.id
+_group.name
+_group.sort_order
+g1;ModelInfo;1
+g2;Quality;2
+g3;Miscellaneous;3
+
+#
+_data_column.primary_key;model_url
+_data_column.default_response_page_size;100
+#
+_data_column.name
+_data_column.code
+_data_column.group_id
+_data_column.data_type
+_data_column.min_col_width
+_data_column.max_col_width
+_data_column.preferred_col_width
+_data_column.is_shown_by_default
+_data_column.is_searchable
+Model id;model_identifier;String;g3;80;150;85;true;false
+Sequence;aligned_sequence;String;g3;80;150;85;false;false
+Provider;provider;String;g1;80;150;85;true;false
+Model Category;model_category;String;g1;80;150;85;true;false
+Uniprot Id;id;String;g1;80;150;85;false;false
+Uniprot Start;uniprot_start;Integer;g1;80;150;85;true;false
+Uniprot End;uniprot_end;Integer;g1;80;150;85;true;false
+Resolution;resolution;double;g2;80;150;85;true;false
+Qmean;qmean_avg_local_score;double;g2;100;150;105;true;false
+Coverage;coverage;double;g2;80;150;85;true;false
+Sequence Identity;sequence_identity;Float;g2;80;150;85;false;false
+Created Date;created;string;g3;80;150;85;true;false
+UniProt Accession;uniprot_accession;String;g1;50;400;95;false;true
+Entry Name;entry_name;String;g3;100;150;105;true;false 
+Url;model_url;String;g3;100;150;105;true;false
index c1dc77c..1edc94b 100755 (executable)
@@ -460,4 +460,21 @@ public class PDBEntry
     }
     return true;
   }
+  
+
+  /**
+   * Permanent URI for retrieving the original structure data
+   * @param urlStr
+   */
+  public void setRetrievalUrl(String urlStr)
+  {
+    setProperty("RETRIEVE_FROM", urlStr);
+  }
+  /**
+   * get the Permanent URI for retrieving the original structure data
+   */
+  public String getRetrievalUrl()
+  {
+    return (String) getProperty("RETRIEVE_FROM");
+  }
 }
index 33b0ed6..31d5c7c 100644 (file)
@@ -22,6 +22,7 @@
 package jalview.fts.api;
 
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 
@@ -88,7 +89,7 @@ public interface FTSRestClientI
 
   /**
    * Fetch index of the primary key column for the dynamic table
-   * 
+   * TODO: consider removing 'hasRefSeq' - never used in code
    * @param wantedFields
    *          the available table columns
    * @param hasRefSeq
@@ -136,4 +137,6 @@ public interface FTSRestClientI
    * @return the default response page size
    */
   public int getDefaultResponsePageSize();
+
+  public String[] getPreferencesColumnsFor(PreferenceSource source);
 }
index e5042ae..0335d65 100644 (file)
@@ -23,6 +23,7 @@ package jalview.fts.core;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.fts.api.StructureFTSRestClientI;
 import jalview.fts.service.pdb.PDBFTSRestClient;
 
 import java.util.ArrayList;
@@ -39,7 +40,13 @@ import javax.swing.SortOrder;
 import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableModel;
 import javax.swing.table.TableRowSorter;
-
+/**
+ * Helps render GUI allowing control of which columns to show for entries returned from an FTS query.
+ * TODO: push down FTSClient specific code
+ * 
+ * @author tcofoegbu
+ *
+ */
 @SuppressWarnings("serial")
 public class FTSDataColumnPreferences extends JScrollPane
 {
@@ -70,7 +77,7 @@ public class FTSDataColumnPreferences extends JScrollPane
     if (source.equals(PreferenceSource.STRUCTURE_CHOOSER)
             || source.equals(PreferenceSource.PREFERENCES))
     {
-      structSummaryColumns = ((PDBFTSRestClient) ftsRestClient)
+      structSummaryColumns = ((StructureFTSRestClientI) ftsRestClient)
               .getAllDefaultDisplayedStructureDataColumns();
     }
     allFTSDataColumns.addAll(ftsRestClient.getAllFTSDataColumns());
@@ -79,28 +86,14 @@ public class FTSDataColumnPreferences extends JScrollPane
     this.getViewport().add(tbl_FTSDataColumnPrefs);
     this.currentSource = source;
 
-    String[] columnNames = null;
-    switch (source)
-    {
-    case SEARCH_SUMMARY:
-      columnNames = new String[] { "", "Display", "Group" };
-      break;
-    case STRUCTURE_CHOOSER:
-      columnNames = new String[] { "", "Display", "Group" };
-      break;
-    case PREFERENCES:
-      columnNames = new String[] { "PDB Field", "Show in search summary",
-          "Show in structure summary" };
-      break;
-    default:
-      break;
-    }
+    String[] columnNames = ftsRestClient.getPreferencesColumnsFor(source);
 
-    Object[][] data = new Object[allFTSDataColumns.size() - 1][3];
+    Object[][] data = new Object[allFTSDataColumns.size()][3];
 
     int x = 0;
     for (FTSDataColumnI field : allFTSDataColumns)
-    {
+    {   
+      //System.out.println("allFTSDataColumns==" + allFTSDataColumns);
       if (field.getName().equalsIgnoreCase("all"))
       {
         continue;
@@ -112,6 +105,7 @@ public class FTSDataColumnPreferences extends JScrollPane
         data[x++] = new Object[] { ftsRestClient
                 .getAllDefaultDisplayedFTSDataColumns().contains(field),
             field.getName(), field.getGroup() };
+        //System.out.println(" PUIS " + field.getName() + " ET AUSSI " + field.getGroup() + "X = " + x);
         break;
       case STRUCTURE_CHOOSER:
         data[x++] = new Object[] { structSummaryColumns.contains(field),
index 7a8a695..f651707 100644 (file)
@@ -30,6 +30,7 @@ import java.util.Objects;
 
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
 import jalview.fts.api.FTSRestClientI;
 
 /**
@@ -504,4 +505,19 @@ public abstract class FTSRestClient implements FTSRestClientI
     return defaultResponsePageSize;
   }
 
+  @Override
+  public String[] getPreferencesColumnsFor(PreferenceSource source)
+  {
+    String[] columnNames = null;
+    switch (source)
+    {
+    case SEARCH_SUMMARY:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    default:
+      // non structure sources don't return any other kind of preferences columns
+      break;
+    }
+    return columnNames;
+  }
 }
index 597bb89..ae50233 100644 (file)
@@ -41,7 +41,7 @@ import javax.swing.table.DefaultTableModel;
 public class FTSRestResponse
 {
   private int numberOfItemsFound;
-
+  
   private String responseTime;
 
   private Collection<FTSData> searchSummary;
index 963778c..04fb17c 100644 (file)
@@ -41,6 +41,9 @@ import jalview.datamodel.SequenceI;
 import jalview.fts.api.FTSData;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.fts.api.StructureFTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
 import jalview.fts.core.FTSRestClient;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
@@ -54,7 +57,7 @@ import jalview.util.Platform;
  * 
  * @author tcnofoegbu
  */
-public class PDBFTSRestClient extends FTSRestClient
+public class PDBFTSRestClient extends FTSRestClient implements StructureFTSRestClientI
 {
 
   private static FTSRestClientI instance = null;
@@ -166,7 +169,7 @@ public class PDBFTSRestClient extends FTSRestClient
 
       URI uri = webResource.getURI();
 
-      // System.out.println(uri);
+      System.out.println(uri);
 
       // Execute the REST request
       ClientResponse clientResponse = webResource
@@ -177,7 +180,7 @@ public class PDBFTSRestClient extends FTSRestClient
       Map<String, Object> jsonObj = null;
       String responseString = null;
 
-      // System.out.println("query >>>>>>> " + pdbRestRequest.toString());
+      System.out.println("query >>>>>>> " + pdbRestRequest.toString());
 
       // Check the response status and report exception if one occurs
       int responseStatus = clientResponse.getStatus();
@@ -368,8 +371,10 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
 
     for (FTSDataColumnI field : diplayFields)
     {
+      //System.out.println("Field " + field);
       String fieldData = (pdbJsonDoc.get(field.getCode()) == null) ? ""
               : pdbJsonDoc.get(field.getCode()).toString();
+      //System.out.println("Field Data : " + fieldData);
       if (field.isPrimaryKeyColumn())
       {
         primaryKey = fieldData;
@@ -472,7 +477,7 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
   }
 
   private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
-
+  @Override
   public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
   {
     if (allDefaultDisplayedStructureDataColumns == null
@@ -484,6 +489,24 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
     }
     return allDefaultDisplayedStructureDataColumns;
   }
-  
-  
+  @Override
+  public String[] getPreferencesColumnsFor(PreferenceSource source) {
+    String[] columnNames = null;
+    switch (source)
+    {
+    case SEARCH_SUMMARY:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case STRUCTURE_CHOOSER:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case PREFERENCES:
+      columnNames = new String[] { "PDB Field", "Show in search summary",
+          "Show in structure summary" };
+      break;
+    default:
+      break;
+    }
+    return columnNames;
+  }
 }
diff --git a/src/jalview/fts/service/threedbeacons/.gitignore b/src/jalview/fts/service/threedbeacons/.gitignore
new file mode 100644 (file)
index 0000000..9a003b7
--- /dev/null
@@ -0,0 +1 @@
+/tdbresttest2.java
diff --git a/src/jalview/fts/service/threedbeacons/TDBeaconsFTSPanel.java b/src/jalview/fts/service/threedbeacons/TDBeaconsFTSPanel.java
new file mode 100644 (file)
index 0000000..7fa6aa5
--- /dev/null
@@ -0,0 +1,280 @@
+package jalview.fts.service.threedbeacons;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.swing.SwingUtilities;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentI;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.core.GFTSPanel;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.gui.SequenceFetcher;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileFormatI;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.util.MessageManager;
+
+@SuppressWarnings("serial")
+public class TDBeaconsFTSPanel extends GFTSPanel
+{
+  private static String defaultFTSFrameTitle = MessageManager
+          .getString("label.pdb_sequence_fetcher");
+
+  private static Map<String, Integer> tempUserPrefs = new HashMap<>();
+
+  private static final String THREEDB_FTS_CACHE_KEY = "CACHE.THREEDB_FTS";
+
+  private static final String THREEDB_AUTOSEARCH = "FTS.THREEDB.AUTOSEARCH";
+
+  private static HttpURLConnection connection;
+
+  public TDBeaconsFTSPanel(SequenceFetcher fetcher)
+  {
+    // no ID retrieval option for TD Beacons just now
+    super(null);
+    pageLimit = TDBeaconsFTSRestClient.getInstance()
+            .getDefaultResponsePageSize();
+    this.seqFetcher = fetcher;
+    this.progressIndicator = (fetcher == null) ? null
+            : fetcher.getProgressIndicator();
+  }
+
+  @Override
+  public void searchAction(boolean isFreshSearch)
+  {
+    mainFrame.requestFocusInWindow();
+    if (isFreshSearch)
+    {
+      offSet = 0;
+    }
+    new Thread()
+    {
+      @Override
+      public void run()
+      {
+        reset();
+        boolean allowEmptySequence = false;
+        if (getTypedText().length() > 0)
+        {
+          setSearchInProgress(true);
+          long startTime = System.currentTimeMillis();
+
+          String searchTarget = ((FTSDataColumnI) cmb_searchTarget
+                  .getSelectedItem()).getCode();
+          wantedFields = TDBeaconsFTSRestClient.getInstance()
+                  .getAllDefaultDisplayedFTSDataColumns();
+          String searchTerm = getTypedText(); // to add : decodeSearchTerm
+
+          FTSRestRequest request = new FTSRestRequest();
+          request.setAllowEmptySeq(allowEmptySequence);
+          request.setResponseSize(100);
+          // expect it to be uniprot accesssion
+          request.setSearchTerm(searchTerm + ".json");
+          request.setOffSet(offSet);
+          request.setWantedFields(wantedFields);
+          FTSRestClientI tdbRestClient = TDBeaconsFTSRestClient
+                  .getInstance();
+          FTSRestResponse resultList;
+          try
+          {
+            resultList = tdbRestClient.executeRequest(request);
+          } catch (Exception e)
+          {
+            setErrorMessage(e.getMessage());
+            checkForErrors();
+            setSearchInProgress(false);
+            return;
+          }
+
+          if (resultList.getSearchSummary() != null
+                  && resultList.getSearchSummary().size() > 0)
+          {
+            getResultTable().setModel(FTSRestResponse.getTableModel(request,
+                    resultList.getSearchSummary()));
+            FTSRestResponse.configureTableColumn(getResultTable(),
+                    wantedFields, tempUserPrefs);
+            getResultTable().setVisible(true);
+          }
+
+          long endTime = System.currentTimeMillis();
+          totalResultSetCount = resultList.getNumberOfItemsFound();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
+          String result = (resultSetCount > 0)
+                  ? MessageManager.getString("label.results")
+                  : MessageManager.getString("label.result");
+
+          if (isPaginationEnabled() && resultSetCount > 0)
+          {
+            String f1 = totalNumberformatter
+                    .format(Integer.valueOf(offSet + 1));
+            String f2 = totalNumberformatter
+                    .format(Integer.valueOf(offSet + resultSetCount));
+            String f3 = totalNumberformatter
+                    .format(Integer.valueOf(totalResultSetCount));
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
+                    + " " + f1 + " to " + f2 + " of " + f3 + " " + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
+          else
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - "
+                    + resultSetCount + " " + result + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
+
+          setSearchInProgress(false);
+          refreshPaginatorState();
+          updateSummaryTableSelections();
+        }
+        txt_search.updateCache();
+      }
+    }.start();
+  }
+
+  @Override
+  public void okAction()
+  {
+    // mainFrame.dispose();
+    disableActionButtons();
+    StringBuilder selectedIds = new StringBuilder();
+    final HashSet<String> selectedIdsSet = new HashSet<>();
+    int primaryKeyColIndex = 0;
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient()
+              .getPrimaryKeyColumIndex(wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    int[] selectedRows = getResultTable().getSelectedRows();
+    String searchTerm = getTypedText();
+    for (int summaryRow : selectedRows)
+    {
+      String idStr = getResultTable()
+              .getValueAt(summaryRow, primaryKeyColIndex).toString();
+      selectedIdsSet.add(idStr);
+    }
+
+    for (String idStr : paginatorCart)
+    {
+      selectedIdsSet.add(idStr);
+    }
+
+    for (String selectedId : selectedIdsSet)
+    {
+      selectedIds.append(selectedId).append(";");
+    }
+
+    SwingUtilities.invokeLater(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        AlignmentI allSeqs = null;
+        FormatAdapter fl = new jalview.io.FormatAdapter();
+        for (String tdbURL : selectedIdsSet)
+        {
+          try
+          {
+            // retrieve the structure via its URL
+            AlignmentI tdbAl = fl.readFile(tdbURL, DataSourceType.URL,
+                    FileFormat.MMCif);
+
+            // TODO: pad structure according to its Uniprot Start so all line up w.r.t. the Uniprot reference sequence
+            // TODO: give the structure a sensible name (not the giant URL *:o) )
+            if (tdbAl != null)
+            {
+              if (allSeqs != null)
+              {
+                allSeqs.append(tdbAl);
+              }
+              else
+              {
+                allSeqs = tdbAl;
+              }
+            }
+          } catch (Exception x)
+          {
+            Cache.log.warn(
+                    "Couldn't retrieve 3d-beacons model for uniprot id"
+                            + searchTerm + " : " + tdbURL,
+                    x);
+          }
+        }
+        seqFetcher.parseResult(allSeqs,
+                "3D-Beacons models for " + searchTerm, FileFormat.MMCif,
+                null);
+
+      }
+    });
+    delayAndEnableActionButtons();
+  }
+
+  @Override
+  public FTSRestClientI getFTSRestClient()
+  {
+    return TDBeaconsFTSRestClient.getInstance();
+  }
+
+  @Override
+  public String getFTSFrameTitle()
+  {
+    return defaultFTSFrameTitle;
+  }
+
+  @Override
+  public boolean isPaginationEnabled()
+  {
+    return true;
+  }
+
+  @Override
+  public Map<String, Integer> getTempUserPrefs()
+  {
+    return tempUserPrefs;
+  }
+
+  @Override
+  public String getCacheKey()
+  {
+    return THREEDB_FTS_CACHE_KEY;
+  }
+
+  @Override
+  public String getAutosearchPreference()
+  {
+    return THREEDB_AUTOSEARCH;
+  }
+
+  @Override
+  protected void showHelp()
+  {
+    System.out.println("No help implemented yet.");
+
+  }
+
+  public static String decodeSearchTerm(String enteredText)
+  {
+    // no multiple query support yet
+    return enteredText;
+  }
+}
diff --git a/src/jalview/fts/service/threedbeacons/TDBeaconsFTSRestClient.java b/src/jalview/fts/service/threedbeacons/TDBeaconsFTSRestClient.java
new file mode 100644 (file)
index 0000000..a57cf3b
--- /dev/null
@@ -0,0 +1,368 @@
+package jalview.fts.service.threedbeacons;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.ws.rs.core.MediaType;
+
+import org.json.simple.parser.ParseException;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.api.StructureFTSRestClientI;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.util.JSONUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
+public class TDBeaconsFTSRestClient extends FTSRestClient
+        implements StructureFTSRestClientI
+{
+  private static final String DEFAULT_THREEDBEACONS_DOMAIN = "https://wwwdev.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/";
+
+  private static FTSRestClientI instance = null;
+
+  protected TDBeaconsFTSRestClient()
+  {
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public FTSRestResponse executeRequest(FTSRestRequest tdbRestRequest)
+          throws Exception
+  {
+    try
+    {
+      String query = tdbRestRequest.getSearchTerm();
+      Client client;
+      Class<ClientResponse> clientResponseClass;
+      if (Platform.isJS())
+      {
+        // JavaScript only
+        client = (Client) (Object) new jalview.javascript.web.Client();
+        clientResponseClass = (Class<ClientResponse>) (Object) jalview.javascript.web.ClientResponse.class;
+      }
+      else
+      /**
+       * Java only
+       * 
+       * @j2sIgnore
+       */
+      {
+        client = Client.create(new DefaultClientConfig());
+        clientResponseClass = ClientResponse.class;
+      }
+      WebResource webResource;
+      webResource = client.resource(DEFAULT_THREEDBEACONS_DOMAIN)
+              .path(query);
+      URI uri = webResource.getURI();
+      System.out.println(uri.toString());
+
+      // Execute the REST request
+      ClientResponse clientResponse = webResource
+              .accept(MediaType.APPLICATION_JSON).get(clientResponseClass);
+
+      // Get the JSON string from the response object or directly from the
+      // client (JavaScript)
+      Map<String, Object> jsonObj = null;
+      String responseString = null;
+
+      // Check the response status and report exception if one occurs
+      int responseStatus = clientResponse.getStatus();
+      switch (responseStatus)
+      {
+      // if success
+      case 200:
+        if (Platform.isJS())
+        {
+          jsonObj = clientResponse.getEntity(Map.class);
+        }
+        else
+        {
+          responseString = clientResponse.getEntity(String.class);
+        }
+        break;
+      case 400:
+        throw new Exception(parseJsonExceptionString(responseString));
+      default:
+        throw new Exception(
+                getMessageByHTTPStatusCode(responseStatus, "3DBeacons"));
+      }
+      // Process the response and return the result to the caller.
+      return parseTDBeaconsJsonResponse(responseString, jsonObj,
+              tdbRestRequest);
+    } catch (Exception e)
+    {
+      String exceptionMsg = e.getMessage();
+      if (exceptionMsg.contains("SocketException"))
+      {
+        // No internet connection
+        throw new Exception(MessageManager.getString(
+                "exception.unable_to_detect_internet_connection"));
+      }
+      else if (exceptionMsg.contains("UnknownHostException"))
+      {
+        // The server is unreachable
+        throw new Exception(MessageManager.formatMessage(
+                "exception.fts_server_unreachable", "3DB Hub"));
+      }
+      else
+      {
+        throw e;
+      }
+    }
+
+  }
+
+  public String setSearchTerm(String term)
+  {
+    return term;
+  }
+
+  public static FTSRestResponse parseTDBeaconsJsonResponse(
+          String tdbJsonResponseString, FTSRestRequest tdbRestRequest)
+  {
+    return parseTDBeaconsJsonResponse(tdbJsonResponseString,
+            (Map<String, Object>) null, tdbRestRequest);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static FTSRestResponse parseTDBeaconsJsonResponse(
+          String tdbJsonResponseString, Map<String, Object> jsonObj,
+          FTSRestRequest tdbRestRequest)
+  {
+    FTSRestResponse searchResult = new FTSRestResponse();
+    List<FTSData> result = null;
+
+    try
+    {
+      if (jsonObj == null)
+      {
+        jsonObj = (Map<String, Object>) JSONUtils
+                .parse(tdbJsonResponseString);
+      }
+
+      Object uniprot_entry = jsonObj.get("uniprot_entry");
+      // TODO: decide if anything from uniprot_entry needs to be reported via
+      // the FTSRestResponse object
+      // Arnaud added seqLength = (Long) ((Map<String, Object>)
+      // jsonObj.get("uniprot_entry")).get("sequence_length");
+
+      List<Object> structures = (List<Object>) jsonObj.get("structures");
+      result = new ArrayList<>();
+
+      int numFound = 0;
+      for (Iterator<Object> strucIter = structures.iterator(); strucIter
+              .hasNext();)
+      {
+        Map<String, Object> structure = (Map<String, Object>) strucIter
+                .next();
+        result.add(getFTSData(structure, tdbRestRequest));
+        numFound++;
+      }
+
+      searchResult.setNumberOfItemsFound(numFound);
+      searchResult.setSearchSummary(result);
+
+    } catch (ParseException e)
+    {
+      e.printStackTrace();
+    }
+    return searchResult;
+  }
+
+  private static FTSData getFTSData(Map<String, Object> tdbJsonStructure,
+          FTSRestRequest tdbRequest)
+  {
+    // TODO: consider reusing PDBFTSRestClient.getFTSData ?
+
+    String primaryKey = null;
+    Object[] summaryRowData;
+
+    SequenceI associatedSequence;
+
+    Collection<FTSDataColumnI> displayFields = tdbRequest.getWantedFields();
+    SequenceI associatedSeq = tdbRequest.getAssociatedSequence();
+    int colCounter = 0;
+    summaryRowData = new Object[(associatedSeq != null)
+                                ? displayFields.size() + 1
+                                : displayFields.size()];
+                        if (associatedSeq != null)
+                        {
+                          associatedSequence = associatedSeq;
+                          summaryRowData[0] = associatedSequence;
+                          colCounter = 1;
+                        }
+
+    for (FTSDataColumnI field : displayFields)
+    {
+      String fieldData = (tdbJsonStructure.get(field.getCode()) == null)
+              ? " "
+              : tdbJsonStructure.get(field.getCode()).toString();
+      // System.out.println("Field : " + field + " Data : " + fieldData);
+      if (field.isPrimaryKeyColumn())
+      {
+        primaryKey = fieldData;
+        summaryRowData[colCounter++] = primaryKey;
+      }
+      else if (fieldData == null || fieldData.trim().isEmpty())
+      {
+        summaryRowData[colCounter++] = null;
+      }
+      else
+      {
+        try
+        {
+          summaryRowData[colCounter++] = (field.getDataType()
+                  .getDataTypeClass() == Integer.class)
+                          ? Integer.valueOf(fieldData)
+                          : (field.getDataType()
+                                  .getDataTypeClass() == Double.class)
+                                          ? Double.valueOf(fieldData)
+                                          : fieldData;
+        } catch (Exception e)
+        {
+          // e.printStackTrace();
+          System.out.println("offending value:" + fieldData + fieldData);
+        }
+      }
+    }
+    final String primaryKey1 = primaryKey;
+    final Object[] summaryRowData1 = summaryRowData;
+
+    return new FTSData()
+    {
+
+      @Override
+      public Object[] getSummaryData()
+      {
+        return summaryRowData1;
+      }
+
+      @Override
+      public Object getPrimaryKey()
+      {
+        return primaryKey1;
+      }
+
+      /**
+       * Returns a string representation of this object;
+       */
+      @Override
+      public String toString()
+      {
+        StringBuilder summaryFieldValues = new StringBuilder();
+        for (Object summaryField : summaryRowData1)
+        {
+          summaryFieldValues.append(
+                  summaryField == null ? " " : summaryField.toString())
+                  .append("\t");
+        }
+        return summaryFieldValues.toString();
+      }
+
+      /**
+       * Returns hash code value for this object
+       */
+      @Override
+      public int hashCode()
+      {
+        return Objects.hash(primaryKey1, this.toString());
+      }
+
+      @Override
+      public boolean equals(Object that)
+      {
+        return this.toString().equals(that.toString());
+      }
+    };
+  }
+
+  // private static FTSData getFTSData(Map<String, Object> doc,
+  // FTSRestRequest tdbRestRequest)
+  // {
+  // String primaryKey = null;
+  //
+  // Object[] summaryRowData;
+  //
+  // Collection<FTSDataColumnI> displayFields =
+  // tdbRestRequest.getWantedFields();
+  // int colCounter = 0;
+  // summaryRowData = new Object[displayFields.size() + 1];
+  //
+  // return null;
+  // }
+
+  private String parseJsonExceptionString(String jsonErrorString)
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String getColumnDataConfigFileName()
+  {
+    return "/fts/tdbeacons_data_columns.txt";
+  }
+
+  public static FTSRestClientI getInstance()
+  {
+    if (instance == null)
+    {
+      instance = new TDBeaconsFTSRestClient();
+    }
+    return instance;
+  }
+
+  private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
+
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
+  {
+    if (allDefaultDisplayedStructureDataColumns == null
+            || allDefaultDisplayedStructureDataColumns.isEmpty())
+    {
+      allDefaultDisplayedStructureDataColumns = new ArrayList<>();
+      allDefaultDisplayedStructureDataColumns
+              .addAll(super.getAllDefaultDisplayedFTSDataColumns());
+    }
+    return allDefaultDisplayedStructureDataColumns;
+  }
+
+  @Override
+  public String[] getPreferencesColumnsFor(PreferenceSource source)
+  {
+    String[] columnNames = null;
+    switch (source)
+    {
+    case SEARCH_SUMMARY:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case STRUCTURE_CHOOSER:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case PREFERENCES:
+      columnNames = new String[] { "3DB Beacons Field", "Show in search summary",
+          "Show in structure summary" };
+      break;
+    default:
+      break;
+    }
+    return columnNames;
+  }
+}
index 8b5d3b7..7f9d4c7 100755 (executable)
@@ -27,6 +27,7 @@ import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceI;
 import jalview.fts.core.GFTSPanel;
 import jalview.fts.service.pdb.PDBFTSPanel;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSPanel;
 import jalview.fts.service.uniprot.UniprotFTSPanel;
 import jalview.io.FileFormatI;
 import jalview.io.gff.SequenceOntologyI;
@@ -195,6 +196,11 @@ public class SequenceFetcher extends JPanel implements Runnable
           frame.dispose();
           new UniprotFTSPanel(SequenceFetcher.this);
         }
+        else if ("3d-beacons".equalsIgnoreCase(currentSelection))
+        {
+          frame.dispose();
+          new TDBeaconsFTSPanel(SequenceFetcher.this);
+        }
         else
         {
           otherSourceAction();
@@ -797,8 +803,15 @@ public class SequenceFetcher extends JPanel implements Runnable
   {
     return "Retrieved from " + database.getSelectedItem();
   }
-
-  AlignmentI parseResult(AlignmentI al, String title,
+  /**
+   * constructs an alignment frame given the data and metadata
+   * @param al
+   * @param title
+   * @param currentFileFormat
+   * @param preferredFeatureColours
+   * @return the alignment 
+   */
+  public AlignmentI parseResult(AlignmentI al, String title,
           FileFormatI currentFileFormat,
           FeatureSettingsModelI preferredFeatureColours)
   {
index 33d8c33..ea2d50d 100644 (file)
@@ -31,11 +31,15 @@ import jalview.datamodel.SequenceI;
 import jalview.fts.api.FTSData;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
+import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.io.DataSourceType;
 import jalview.jbgui.GStructureChooser;
+import jalview.jbgui.GStructureChooser.FilterOption;
 import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
@@ -71,8 +75,6 @@ public class StructureChooser extends GStructureChooser
 {
   private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
 
-  private static int MAX_QLENGTH = 7820;
-
   private SequenceI selectedSequence;
 
   private SequenceI[] selectedSequences;
@@ -81,9 +83,13 @@ public class StructureChooser extends GStructureChooser
 
   private Collection<FTSData> discoveredStructuresSet;
 
-  private FTSRestRequest lastPdbRequest;
+  private StructureChooserQuerySource data;
 
-  private FTSRestClientI pdbRestClient;
+  @Override
+  protected FTSDataColumnPreferences getFTSDocFieldPrefs()
+  {
+    return data.getDocFieldPrefs();
+  }
 
   private String selectedPdbFileName;
 
@@ -96,11 +102,17 @@ public class StructureChooser extends GStructureChooser
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap)
   {
+    // which FTS engine to use
+    data = StructureChooserQuerySource
+            .getTDBfts();
+    initDialog();
+    
     this.ap = ap;
     this.selectedSequence = selectedSeq;
     this.selectedSequences = selectedSeqs;
     this.progressIndicator = (ap == null) ? null : ap.alignFrame;
     init();
+    
   }
 
   /**
@@ -165,8 +177,7 @@ public class StructureChooser extends GStructureChooser
 
         if (view.isLinkedWith(ap))
         {
-          targetView.insertItemAt(viewHandler,
-                  linkedViewsAt++);
+          targetView.insertItemAt(viewHandler, linkedViewsAt++);
         }
         else
         {
@@ -217,36 +228,35 @@ public class StructureChooser extends GStructureChooser
   void fetchStructuresMetaData()
   {
     long startTime = System.currentTimeMillis();
-    pdbRestClient = PDBFTSRestClient.getInstance();
-    Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+    Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
             .getStructureSummaryFields();
 
     discoveredStructuresSet = new LinkedHashSet<>();
     HashSet<String> errors = new HashSet<>();
+
+    FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+            .getSelectedItem());
+
     for (SequenceI seq : selectedSequences)
     {
-      FTSRestRequest pdbRequest = new FTSRestRequest();
-      pdbRequest.setAllowEmptySeq(false);
-      pdbRequest.setResponseSize(500);
-      pdbRequest.setFieldToSearchBy("(");
-      FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
-              .getSelectedItem());
-      pdbRequest.setFieldToSortBy(selectedFilterOpt.getValue(),
-              !chk_invertFilter.isSelected());
-      pdbRequest.setWantedFields(wantedFields);
-      pdbRequest.setSearchTerm(buildQuery(seq) + ")");
-      pdbRequest.setAssociatedSequence(seq);
+
       FTSRestResponse resultList;
       try
       {
-        resultList = pdbRestClient.executeRequest(pdbRequest);
+        resultList = data.fetchStructuresMetaData(seq, wantedFields,
+                selectedFilterOpt, !chk_invertFilter.isSelected());
+        // null response means the FTSengine didn't yield a query for this
+        // consider designing a special exception if we really wanted to be OOCrazy
+        if (resultList==null)
+        {
+          continue;
+        }
       } catch (Exception e)
       {
         e.printStackTrace();
         errors.add(e.getMessage());
         continue;
       }
-      lastPdbRequest = pdbRequest;
       if (resultList.getSearchSummary() != null
               && !resultList.getSearchSummary().isEmpty())
       {
@@ -260,8 +270,8 @@ public class StructureChooser extends GStructureChooser
     if (discoveredStructuresSet != null
             && !discoveredStructuresSet.isEmpty())
     {
-      getResultTable().setModel(FTSRestResponse
-              .getTableModel(lastPdbRequest, discoveredStructuresSet));
+      getResultTable()
+              .setModel(data.getTableModel(discoveredStructuresSet));
       noOfStructuresFound = discoveredStructuresSet.size();
       mainFrame.setTitle(MessageManager.formatMessage(
               "label.structure_chooser_no_of_structures",
@@ -309,157 +319,6 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
-   * Builds a query string for a given sequences using its DBRef entries
-   * 
-   * @param seq
-   *          the sequences to build a query for
-   * @return the built query string
-   */
-
-  static String buildQuery(SequenceI seq)
-  {
-    boolean isPDBRefsFound = false;
-    boolean isUniProtRefsFound = false;
-    StringBuilder queryBuilder = new StringBuilder();
-    Set<String> seqRefs = new LinkedHashSet<>();
-    
-    /*
-     * note PDBs as DBRefEntry so they are not duplicated in query
-     */
-    Set<String> pdbids = new HashSet<>();
-
-    if (seq.getAllPDBEntries() != null
-            && queryBuilder.length() < MAX_QLENGTH)
-    {
-      for (PDBEntry entry : seq.getAllPDBEntries())
-      {
-        if (isValidSeqName(entry.getId()))
-        {
-          String id = entry.getId().toLowerCase();
-          queryBuilder.append("pdb_id:").append(id).append(" OR ");
-          isPDBRefsFound = true;
-          pdbids.add(id);
-        }
-      }
-    }
-
-    List<DBRefEntry> refs = seq.getDBRefs();
-    if (refs != null && refs.size() != 0)
-    {
-      for (int ib = 0, nb = refs.size(); ib < nb; ib++)
-      {
-         DBRefEntry dbRef = refs.get(ib);
-        if (isValidSeqName(getDBRefId(dbRef))
-                && queryBuilder.length() < MAX_QLENGTH)
-        {
-          if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
-          {
-            queryBuilder.append("uniprot_accession:")
-                    .append(getDBRefId(dbRef)).append(" OR ");
-            queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
-                    .append(" OR ");
-            isUniProtRefsFound = true;
-          }
-          else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
-          {
-
-            String id = getDBRefId(dbRef).toLowerCase();
-            if (!pdbids.contains(id))
-            {
-              queryBuilder.append("pdb_id:").append(id).append(" OR ");
-              isPDBRefsFound = true;
-              pdbids.add(id);
-            }
-          }
-          else
-          {
-            seqRefs.add(getDBRefId(dbRef));
-          }
-        }
-      }
-    }
-
-    if (!isPDBRefsFound && !isUniProtRefsFound)
-    {
-      String seqName = seq.getName();
-      seqName = sanitizeSeqName(seqName);
-      String[] names = seqName.toLowerCase().split("\\|");
-      for (String name : names)
-      {
-        // System.out.println("Found name : " + name);
-        name.trim();
-        if (isValidSeqName(name))
-        {
-          seqRefs.add(name);
-        }
-      }
-
-      for (String seqRef : seqRefs)
-      {
-        queryBuilder.append("text:").append(seqRef).append(" OR ");
-      }
-    }
-
-    int endIndex = queryBuilder.lastIndexOf(" OR ");
-    if (queryBuilder.toString().length() < 6)
-    {
-      return null;
-    }
-    String query = queryBuilder.toString().substring(0, endIndex);
-    return query;
-  }
-
-  /**
-   * Remove the following special characters from input string +, -, &, !, (, ),
-   * {, }, [, ], ^, ", ~, *, ?, :, \
-   * 
-   * @param seqName
-   * @return
-   */
-  static String sanitizeSeqName(String seqName)
-  {
-    Objects.requireNonNull(seqName);
-    return seqName.replaceAll("\\[\\d*\\]", "")
-            .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
-  }
-
-  /**
-   * Ensures sequence ref names are not less than 3 characters and does not
-   * contain a database name
-   * 
-   * @param seqName
-   * @return
-   */
-  static boolean isValidSeqName(String seqName)
-  {
-    // System.out.println("seqName : " + seqName);
-    String ignoreList = "pdb,uniprot,swiss-prot";
-    if (seqName.length() < 3)
-    {
-      return false;
-    }
-    if (seqName.contains(":"))
-    {
-      return false;
-    }
-    seqName = seqName.toLowerCase();
-    for (String ignoredEntry : ignoreList.split(","))
-    {
-      if (seqName.contains(ignoredEntry))
-      {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  static String getDBRefId(DBRefEntry dbRef)
-  {
-    String ref = dbRef.getAccessionId().replaceAll("GO:", "");
-    return ref;
-  }
-
-  /**
    * Filters a given list of discovered structures based on supplied argument
    * 
    * @param fieldToFilterBy
@@ -473,50 +332,27 @@ public class StructureChooser extends GStructureChooser
       public void run()
       {
         long startTime = System.currentTimeMillis();
-        pdbRestClient = PDBFTSRestClient.getInstance();
         lbl_loading.setVisible(true);
-        Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+        Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
                 .getStructureSummaryFields();
         Collection<FTSData> filteredResponse = new HashSet<>();
         HashSet<String> errors = new HashSet<>();
 
         for (SequenceI seq : selectedSequences)
         {
-          FTSRestRequest pdbRequest = new FTSRestRequest();
-          if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
-          {
-            pdbRequest.setAllowEmptySeq(false);
-            pdbRequest.setResponseSize(1);
-            pdbRequest.setFieldToSearchBy("(");
-            pdbRequest.setSearchTerm(buildQuery(seq) + ")");
-            pdbRequest.setWantedFields(wantedFields);
-            pdbRequest.setAssociatedSequence(seq);
-            pdbRequest.setFacet(true);
-            pdbRequest.setFacetPivot(fieldToFilterBy + ",entry_entity");
-            pdbRequest.setFacetPivotMinCount(1);
-          }
-          else
-          {
-            pdbRequest.setAllowEmptySeq(false);
-            pdbRequest.setResponseSize(1);
-            pdbRequest.setFieldToSearchBy("(");
-            pdbRequest.setFieldToSortBy(fieldToFilterBy,
-                    !chk_invertFilter.isSelected());
-            pdbRequest.setSearchTerm(buildQuery(seq) + ")");
-            pdbRequest.setWantedFields(wantedFields);
-            pdbRequest.setAssociatedSequence(seq);
-          }
+
           FTSRestResponse resultList;
           try
           {
-            resultList = pdbRestClient.executeRequest(pdbRequest);
+            resultList = data.selectFirstRankedQuery(seq, wantedFields,
+                    fieldToFilterBy, !chk_invertFilter.isSelected());
+
           } catch (Exception e)
           {
             e.printStackTrace();
             errors.add(e.getMessage());
             continue;
           }
-          lastPdbRequest = pdbRequest;
           if (resultList.getSearchSummary() != null
                   && !resultList.getSearchSummary().isEmpty())
           {
@@ -532,8 +368,8 @@ public class StructureChooser extends GStructureChooser
           Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
           reorderedStructuresSet.addAll(filteredResponse);
           reorderedStructuresSet.addAll(discoveredStructuresSet);
-          getResultTable().setModel(FTSRestResponse
-                  .getTableModel(lastPdbRequest, reorderedStructuresSet));
+          getResultTable()
+                  .setModel(data.getTableModel(reorderedStructuresSet));
 
           FTSRestResponse.configureTableColumn(getResultTable(),
                   wantedFields, tempUserPrefs);
@@ -577,7 +413,8 @@ public class StructureChooser extends GStructureChooser
   @Override
   protected void pdbFromFile_actionPerformed()
   {
-    // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and StructureChooser
+    // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
+    // StructureChooser
     // works
     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
@@ -639,8 +476,8 @@ public class StructureChooser extends GStructureChooser
     if (cachedPDBExist)
     {
       FilterOption cachedOption = new FilterOption(
-              MessageManager.getString("label.cached_structures"),
-              "-", VIEWS_LOCAL_PDB, false);
+              MessageManager.getString("label.cached_structures"), "-",
+              VIEWS_LOCAL_PDB, false);
       cmb_filterOption.addItem(cachedOption);
       cmb_filterOption.setSelectedItem(cachedOption);
     }
@@ -861,7 +698,7 @@ public class StructureChooser extends GStructureChooser
     }
     return found;
   }
-  
+
   /**
    * Handles the 'New View' action
    */
@@ -906,37 +743,11 @@ public class StructureChooser extends GStructureChooser
 
         if (currentView == VIEWS_FILTER)
         {
-          int pdbIdColIndex = restable.getColumn("PDB Id")
-                  .getModelIndex();
-          int refSeqColIndex = restable.getColumn("Ref Sequence")
-                  .getModelIndex();
           int[] selectedRows = restable.getSelectedRows();
           PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
-          int count = 0;
           List<SequenceI> selectedSeqsToView = new ArrayList<>();
-          for (int row : selectedRows)
-          {
-            String pdbIdStr = restable
-                    .getValueAt(row, pdbIdColIndex).toString();
-            SequenceI selectedSeq = (SequenceI) restable
-                    .getValueAt(row, refSeqColIndex);
-            selectedSeqsToView.add(selectedSeq);
-            PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
-            if (pdbEntry == null)
-            {
-              pdbEntry = getFindEntry(pdbIdStr,
-                      selectedSeq.getAllPDBEntries());
-            }
+          pdbEntriesToView = data.collectSelectedRows(restable,selectedRows,selectedSeqsToView);
 
-            if (pdbEntry == null)
-            {
-              pdbEntry = new PDBEntry();
-              pdbEntry.setId(pdbIdStr);
-              pdbEntry.setType(PDBEntry.Type.PDB);
-              selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
-            }
-            pdbEntriesToView[count++] = pdbEntry;
-          }
           SequenceI[] selectedSeqs = selectedSeqsToView
                   .toArray(new SequenceI[selectedSeqsToView.size()]);
           sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
@@ -1010,10 +821,8 @@ public class StructureChooser extends GStructureChooser
                           DataSourceType.FILE, selectedSequence, true,
                           Desktop.instance);
 
-          sViewer = launchStructureViewer(
-                  ssm, new PDBEntry[]
-                  { fileEntry }, ap,
-                  new SequenceI[]
+          sViewer = launchStructureViewer(ssm, new PDBEntry[] { fileEntry },
+                  ap, new SequenceI[]
                   { selectedSequence });
         }
         SwingUtilities.invokeLater(new Runnable()
@@ -1046,21 +855,6 @@ public class StructureChooser extends GStructureChooser
     }
   }
 
-  private PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
-  {
-    Objects.requireNonNull(id);
-    Objects.requireNonNull(pdbEntries);
-    PDBEntry foundEntry = null;
-    for (PDBEntry entry : pdbEntries)
-    {
-      if (entry.getId().equalsIgnoreCase(id))
-      {
-        return entry;
-      }
-    }
-    return foundEntry;
-  }
-
   /**
    * Answers a structure viewer (new or existing) configured to superimpose
    * added structures or not according to the user's choice
@@ -1068,8 +862,7 @@ public class StructureChooser extends GStructureChooser
    * @param ssm
    * @return
    */
-  StructureViewer getTargetedStructureViewer(
-          StructureSelectionManager ssm)
+  StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
   {
     Object sv = targetView.getSelectedItem();
 
@@ -1086,8 +879,7 @@ public class StructureChooser extends GStructureChooser
    * @return
    */
   private StructureViewer launchStructureViewer(
-          StructureSelectionManager ssm,
-          final PDBEntry[] pdbEntriesToView,
+          StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
           final AlignmentPanel alignPanel, SequenceI[] sequences)
   {
     long progressId = sequences.hashCode();
@@ -1150,8 +942,9 @@ public class StructureChooser extends GStructureChooser
     }
     if (pdbEntriesToView.length > 1)
     {
-      setProgressBar(MessageManager.getString(
-              "status.fetching_3d_structures_for_selected_entries"),
+      setProgressBar(
+              MessageManager.getString(
+                      "status.fetching_3d_structures_for_selected_entries"),
               progressId);
       theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
     }
@@ -1159,7 +952,7 @@ public class StructureChooser extends GStructureChooser
     {
       setProgressBar(MessageManager.formatMessage(
               "status.fetching_3d_structures_for",
-              pdbEntriesToView[0].getId()),progressId);
+              pdbEntriesToView[0].getId()), progressId);
       theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
     }
     setProgressBar(null, progressId);
@@ -1204,7 +997,8 @@ public class StructureChooser extends GStructureChooser
             && !discoveredStructuresSet.isEmpty();
   }
 
-  protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes this. 
+  protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
+                               // this.
   // Doing a search for "1" or "1c" is valuable?
   // Those work but are enormously slow.
 
@@ -1212,51 +1006,54 @@ public class StructureChooser extends GStructureChooser
   protected void txt_search_ActionPerformed()
   {
     String text = txt_search.getText().trim();
-       if (text.length() >= PDB_ID_MIN) 
-    new Thread()
-    {
-
-       @Override
-      public void run()
+    if (text.length() >= PDB_ID_MIN)
+      new Thread()
       {
-        errorWarning.setLength(0);
-        isValidPBDEntry = false;
-        if (text.length() > 0)
+
+        @Override
+        public void run()
         {
-          String searchTerm = text.toLowerCase();
-          searchTerm = searchTerm.split(":")[0];
-          // System.out.println(">>>>> search term : " + searchTerm);
-          List<FTSDataColumnI> wantedFields = new ArrayList<>();
-          FTSRestRequest pdbRequest = new FTSRestRequest();
-          pdbRequest.setAllowEmptySeq(false);
-          pdbRequest.setResponseSize(1);
-          pdbRequest.setFieldToSearchBy("(pdb_id:");
-          pdbRequest.setWantedFields(wantedFields);
-          pdbRequest.setSearchTerm(searchTerm + ")");
-          pdbRequest.setAssociatedSequence(selectedSequence);
-          pdbRestClient = PDBFTSRestClient.getInstance();
-          wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
-          FTSRestResponse resultList;
-          try
-          {
-            resultList = pdbRestClient.executeRequest(pdbRequest);
-          } catch (Exception e)
-          {
-            errorWarning.append(e.getMessage());
-            return;
-          } finally
+          errorWarning.setLength(0);
+          isValidPBDEntry = false;
+          if (text.length() > 0)
           {
-            validateSelections();
-          }
-          if (resultList.getSearchSummary() != null
-                  && resultList.getSearchSummary().size() > 0)
-          {
-            isValidPBDEntry = true;
+            // TODO move this pdb id search into the PDB specific
+            // FTSSearchEngine
+            // for moment, it will work fine as is because it is self-contained
+            String searchTerm = text.toLowerCase();
+            searchTerm = searchTerm.split(":")[0];
+            // System.out.println(">>>>> search term : " + searchTerm);
+            List<FTSDataColumnI> wantedFields = new ArrayList<>();
+            FTSRestRequest pdbRequest = new FTSRestRequest();
+            pdbRequest.setAllowEmptySeq(false);
+            pdbRequest.setResponseSize(1);
+            pdbRequest.setFieldToSearchBy("(pdb_id:");
+            pdbRequest.setWantedFields(wantedFields);
+            pdbRequest.setSearchTerm(searchTerm + ")");
+            pdbRequest.setAssociatedSequence(selectedSequence);
+            FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
+            wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
+            FTSRestResponse resultList;
+            try
+            {
+              resultList = pdbRestClient.executeRequest(pdbRequest);
+            } catch (Exception e)
+            {
+              errorWarning.append(e.getMessage());
+              return;
+            } finally
+            {
+              validateSelections();
+            }
+            if (resultList.getSearchSummary() != null
+                    && resultList.getSearchSummary().size() > 0)
+            {
+              isValidPBDEntry = true;
+            }
           }
+          validateSelections();
         }
-        validateSelections();
-      }
-    }.start();
+      }.start();
   }
 
   @Override
@@ -1403,4 +1200,11 @@ public class StructureChooser extends GStructureChooser
   {
     return sViewer == null ? null : sViewer.sview;
   }
+
+  @Override
+  protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
+  {
+    data.setDocFieldPrefs(newPrefs);
+    
+  }
 }
diff --git a/src/jalview/gui/structurechooser/StructureChooserQuerySource.java b/src/jalview/gui/structurechooser/StructureChooserQuerySource.java
new file mode 100644 (file)
index 0000000..9861b1a
--- /dev/null
@@ -0,0 +1,207 @@
+package jalview.gui.structurechooser;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.swing.JTable;
+import javax.swing.table.TableModel;
+
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.jbgui.GStructureChooser.FilterOption;
+
+/**
+ * logic for querying sources of structural data for structures of sequences
+ * 
+ * @author jprocter
+ *
+ * @param <T>
+ */
+public abstract class StructureChooserQuerySource
+{
+  protected FTSRestRequest lastPdbRequest;
+
+  protected FTSRestClientI pdbRestClient;
+
+  protected FTSDataColumnPreferences docFieldPrefs;
+
+  /**
+   * max length of a GET URL (probably :( )
+   */
+  protected static int MAX_QLENGTH = 7820;
+
+  public StructureChooserQuerySource()
+  {
+  }
+
+  public static StructureChooserQuerySource getPDBfts()
+  {
+          return new PDBStructureChooserQuerySource();
+  }
+
+  public static StructureChooserQuerySource getTDBfts()
+  {
+    return new ThreeDBStructureChooserQuerySource();
+  }
+
+  public FTSDataColumnPreferences getDocFieldPrefs()
+  {
+    return docFieldPrefs;
+  }
+
+  public void setDocFieldPrefs(FTSDataColumnPreferences docFieldPrefs)
+  {
+    this.docFieldPrefs = docFieldPrefs;
+  }
+
+  public FTSDataColumnPreferences getInitialFieldPreferences()
+  {
+    return docFieldPrefs;
+  }
+
+
+  /**
+   * Builds a query string for a given sequences using its DBRef entries
+   * 
+   * @param seq
+   *          the sequences to build a query for
+   * @return the built query string
+   */
+
+  public abstract String buildQuery(SequenceI seq);
+  
+
+  /**
+   * Remove the following special characters from input string +, -, &, !, (, ),
+   * {, }, [, ], ^, ", ~, *, ?, :, \
+   * 
+   * @param seqName
+   * @return
+   */
+  public static String sanitizeSeqName(String seqName)
+  {
+    Objects.requireNonNull(seqName);
+    return seqName.replaceAll("\\[\\d*\\]", "")
+            .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
+  }
+
+  /**
+   * Ensures sequence ref names are not less than 3 characters and does not
+   * contain a database name
+   * 
+   * @param seqName
+   * @return
+   */
+  static boolean isValidSeqName(String seqName)
+  {
+    // System.out.println("seqName : " + seqName);
+    String ignoreList = "pdb,uniprot,swiss-prot";
+    if (seqName.length() < 3)
+    {
+      return false;
+    }
+    if (seqName.contains(":"))
+    {
+      return false;
+    }
+    seqName = seqName.toLowerCase();
+    for (String ignoredEntry : ignoreList.split(","))
+    {
+      if (seqName.contains(ignoredEntry))
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  static String getDBRefId(DBRefEntry dbRef)
+  {
+    String ref = dbRef.getAccessionId().replaceAll("GO:", "");
+    return ref;
+  }
+
+  static PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
+  {
+    Objects.requireNonNull(id);
+    Objects.requireNonNull(pdbEntries);
+    PDBEntry foundEntry = null;
+    for (PDBEntry entry : pdbEntries)
+    {
+      if (entry.getId().equalsIgnoreCase(id))
+      {
+        return entry;
+      }
+    }
+    return foundEntry;
+  }
+
+  /**
+   * FTSRestClient specific query builder to recover associated structure data
+   * records for a sequence
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public abstract FTSRestResponse fetchStructuresMetaData(SequenceI seq,
+          Collection<FTSDataColumnI> wantedFields,
+          FilterOption selectedFilterOpt, boolean b) throws Exception;
+
+  /**
+   * FTSRestClient specific query builder to pick top ranked entry from a
+   * fetchStructuresMetaData query
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public abstract FTSRestResponse selectFirstRankedQuery(SequenceI seq,
+          Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
+          boolean b) throws Exception;
+
+  /**
+   * 
+   * @param discoveredStructuresSet
+   * @return the table model for the given result set for this engine
+   */
+  public TableModel getTableModel(
+          Collection<FTSData> discoveredStructuresSet)
+  {
+    return FTSRestResponse.getTableModel(lastPdbRequest,
+            discoveredStructuresSet);
+  }
+
+  public abstract PDBEntry[] collectSelectedRows(JTable restable,
+          int[] selectedRows, List<SequenceI> selectedSeqsToView);
+
+}
\ No newline at end of file
index b9c9267..d43495e 100644 (file)
@@ -161,9 +161,9 @@ public abstract class GStructureChooser extends JPanel
 
   protected JTabbedPane pnl_filter = new JTabbedPane();
 
-  protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
-          PreferenceSource.STRUCTURE_CHOOSER,
-          PDBFTSRestClient.getInstance());
+  protected abstract FTSDataColumnPreferences getFTSDocFieldPrefs();
+  protected abstract void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs);
+
 
   protected FTSDataColumnI[] previousWantedFields;
 
@@ -249,6 +249,10 @@ public abstract class GStructureChooser extends JPanel
 
   public GStructureChooser()
   {
+  }
+  protected void initDialog()
+  {
+
     try
     {
       jbInit();
@@ -261,7 +265,7 @@ public abstract class GStructureChooser extends JPanel
       e.printStackTrace();
     }
   }
-
+  
   // BH SwingJS optimization
   // (a) 100-ms interruptable timer for text entry -- BH 1/10/2019
   // (b) two-character minimum, at least for JavaScript.
@@ -596,7 +600,7 @@ public abstract class GStructureChooser extends JPanel
           btn_add.setVisible(false);
           btn_newView.setEnabled(false);
           btn_cancel.setVisible(false);
-          previousWantedFields = pdbDocFieldPrefs
+          previousWantedFields = getFTSDocFieldPrefs()
                   .getStructureSummaryFields()
                   .toArray(new FTSDataColumnI[0]);
         }
@@ -618,7 +622,7 @@ public abstract class GStructureChooser extends JPanel
     pnl_filter.addChangeListener(changeListener);
     pnl_filter.setPreferredSize(new Dimension(width, height));
     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
-    pnl_filter.add(configureCols, pdbDocFieldPrefs);
+    pnl_filter.add(configureCols, getFTSDocFieldPrefs());
 
     JPanel pnl_locPDB = new JPanel(new BorderLayout());
     pnl_locPDB.add(scrl_localPDB);
@@ -683,7 +687,7 @@ protected void closeAction(int preferredHeight)
       return true;
     }
 
-    FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
+    FTSDataColumnI[] currentWantedFields = getFTSDocFieldPrefs()
             .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
     return Arrays.equals(currentWantedFields, previousWantedFields) ? false
             : true;
index a480176..1661acf 100644 (file)
@@ -27,6 +27,7 @@ import jalview.ws.dbsources.Pdb;
 import jalview.ws.dbsources.PfamFull;
 import jalview.ws.dbsources.PfamSeed;
 import jalview.ws.dbsources.RfamSeed;
+import jalview.ws.dbsources.TDBeacons;
 import jalview.ws.dbsources.Uniprot;
 import jalview.ws.seqfetcher.ASequenceFetcher;
 import jalview.ws.seqfetcher.DbSourceProxy;
@@ -54,6 +55,7 @@ public class SequenceFetcher extends ASequenceFetcher
     addDBRefSourceImpl(EmblSource.class);
     addDBRefSourceImpl(EmblCdsSource.class);
     addDBRefSourceImpl(Uniprot.class);
+    addDBRefSourceImpl(TDBeacons.class);
     addDBRefSourceImpl(Pdb.class);
     addDBRefSourceImpl(PfamFull.class);
     addDBRefSourceImpl(PfamSeed.class);
diff --git a/src/jalview/ws/dbsources/TDBeacons.java b/src/jalview/ws/dbsources/TDBeacons.java
new file mode 100644 (file)
index 0000000..b2fbc17
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.dbsources;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.schemes.ResidueProperties;
+import jalview.util.StringUtils;
+import jalview.ws.seqfetcher.DbSourceProxyImpl;
+import jalview.xml.binding.embl.ROOT;
+import jalview.xml.binding.uniprot.DbReferenceType;
+import jalview.xml.binding.uniprot.Entry;
+import jalview.xml.binding.uniprot.FeatureType;
+import jalview.xml.binding.uniprot.LocationType;
+import jalview.xml.binding.uniprot.PositionType;
+import jalview.xml.binding.uniprot.PropertyType;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import com.stevesoft.pat.Regex;
+
+/**
+ * This class queries the Uniprot database for sequence data, unmarshals the
+ * returned XML, and converts it to Jalview Sequence records (including attached
+ * database references and sequence features)
+ * 
+ * @author JimP
+ * 
+ */
+public class TDBeacons extends DbSourceProxyImpl
+{
+  private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org";
+
+  private static final String BAR_DELIMITER = "|";
+  
+  private static final String DEFAULT_THREEDBEACONS_DOMAIN = "https://wwwdev.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons-hub-api/uniprot/summary/";
+
+  /**
+   * Constructor
+   */
+  public TDBeacons()
+  {
+    super();
+  }
+
+  private String getDomain()
+  {
+    return Cache.getDefault("UNIPROT_DOMAIN", DEFAULT_UNIPROT_DOMAIN);
+    //return Cache.getDefault("3DB_DOMAIN", DEFAULT_THREEDBEACONS_DOMAIN );
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
+   */
+  @Override
+  public String getAccessionSeparator()
+  {
+    return null;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getAccessionValidator()
+   */
+  @Override
+  public Regex getAccessionValidator()
+  {
+    return new Regex("([A-Z]+[0-9]+[A-Z0-9]+|[A-Z0-9]+_[A-Z0-9]+)");
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getDbSource()
+   */
+  @Override
+  public String getDbSource()
+  {
+    return "3d-beacons";// DBRefSource.UNIPROT;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getDbVersion()
+   */
+  @Override
+  public String getDbVersion()
+  {
+    return "0"; // we really don't know what version we're on.
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getSequenceRecords(java.lang.String[])
+   */
+  @Override
+  public AlignmentI getSequenceRecords(String queries) throws Exception
+  {
+    startQuery();
+    try
+    {
+      queries = queries.toUpperCase().replaceAll(
+              "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
+      AlignmentI al = null;
+
+      String downloadstring = getDomain() + "/uniprot/" + queries
+              + ".xml";
+//      String downloadstring = getDomain() + queries + ".json";
+
+      URL url = new URL(downloadstring);
+      URLConnection urlconn = url.openConnection();
+      InputStream istr = urlconn.getInputStream();
+      List<Entry> entries = getUniprotEntries(istr);
+      if (entries != null)
+      {
+        List<SequenceI> seqs = new ArrayList<>();
+        for (Entry entry : entries)
+        {
+          seqs.add(uniprotEntryToSequence(entry));
+        }
+        al = new Alignment(seqs.toArray(new SequenceI[seqs.size()]));
+      }
+
+      stopQuery();
+      return al;
+    } catch (Exception e)
+    {
+      throw (e);
+    } finally
+    {
+      stopQuery();
+    }
+  }
+
+  /**
+   * Converts an Entry object (bound from Uniprot XML) to a Jalview Sequence
+   * 
+   * @param entry
+   * @return
+   */
+  SequenceI uniprotEntryToSequence(Entry entry)
+  {
+    String id = getUniprotEntryId(entry);
+    /*
+     * Sequence should not include any whitespace, but JAXB leaves these in
+     */
+    String seqString = entry.getSequence().getValue().replaceAll("\\s*",
+            "");
+
+    SequenceI sequence = new Sequence(id,
+            seqString);
+    sequence.setDescription(getUniprotEntryDescription(entry));
+
+    /*
+     * add a 'self' DBRefEntry for each accession
+     */
+    final String dbVersion = getDbVersion();
+    List<DBRefEntry> dbRefs = new ArrayList<>();
+    for (String accessionId : entry.getAccession())
+    {
+      DBRefEntry dbRef = new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
+              accessionId);
+      dbRefs.add(dbRef);
+    }
+
+    /*
+     * add a DBRefEntry for each dbReference element in the XML;
+     * also add a PDBEntry if type="PDB";
+     * also add an EMBLCDS dbref if protein sequence id is given
+     * also add an Ensembl dbref " " " " " "
+     */
+    Vector<PDBEntry> pdbRefs = new Vector<>();
+    for (DbReferenceType dbref : entry.getDbReference())
+    {
+      String type = dbref.getType();
+      DBRefEntry dbr = new DBRefEntry(type,
+              DBRefSource.UNIPROT + ":" + dbVersion, dbref.getId());
+      dbRefs.add(dbr);
+      if ("PDB".equals(type))
+      {
+        pdbRefs.add(new PDBEntry(dbr));
+      }
+      if ("EMBL".equals(type))
+      {
+        /*
+         * e.g. Uniprot accession Q9BXM7 has
+         * <dbReference type="EMBL" id="M19359">
+         *   <property type="protein sequence ID" value="AAA40981.1"/>
+         *   <property type="molecule type" value="Genomic_DNA"/>
+         * </dbReference> 
+         */
+        String cdsId = getProperty(dbref.getProperty(),
+                "protein sequence ID");
+        if (cdsId != null && cdsId.trim().length() > 0)
+        {
+          // remove version
+          String[] vrs = cdsId.split("\\.");
+          String version = vrs.length > 1 ? vrs[1]
+                  : DBRefSource.UNIPROT + ":" + dbVersion;
+          dbr = new DBRefEntry(DBRefSource.EMBLCDS, version, vrs[0]);
+          dbRefs.add(dbr);
+        }
+      }
+      if ("Ensembl".equals(type))
+      {
+        /*
+         * e.g. Uniprot accession Q9BXM7 has
+         * <dbReference type="Ensembl" id="ENST00000321556">
+         *   <molecule id="Q9BXM7-1"/>
+         *   <property type="protein sequence ID" value="ENSP00000364204"/>
+         *   <property type="gene ID" value="ENSG00000158828"/>
+         * </dbReference> 
+         */
+        String cdsId = getProperty(dbref.getProperty(),
+                "protein sequence ID");
+        if (cdsId != null && cdsId.trim().length() > 0)
+        {
+          dbr = new DBRefEntry(DBRefSource.ENSEMBL,
+                  DBRefSource.UNIPROT + ":" + dbVersion, cdsId.trim());
+          dbRefs.add(dbr);
+        }
+      }
+    }
+
+    /*
+     * create features; they have either begin and end, or position, in XML
+     */
+    sequence.setPDBId(pdbRefs);
+    if (entry.getFeature() != null)
+    {
+      for (FeatureType uf : entry.getFeature())
+      {
+        LocationType location = uf.getLocation();
+        int start = 0;
+        int end = 0;
+        if (location.getPosition() != null)
+        {
+          start = location.getPosition().getPosition().intValue();
+          end = start;
+        }
+        else
+        {
+          start = location.getBegin().getPosition().intValue();
+          end = location.getEnd().getPosition().intValue();
+        }
+        SequenceFeature sf = new SequenceFeature(uf.getType(),
+                getDescription(uf), start, end, "Uniprot");
+        sf.setStatus(uf.getStatus());
+        sequence.addSequenceFeature(sf);
+      }
+    }
+    for (DBRefEntry dbr : dbRefs)
+    {
+      sequence.addDBRef(dbr);
+    }
+    return sequence;
+  }
+
+  /**
+   * A helper method that builds a sequence feature description
+   * 
+   * @param feature
+   * @return
+   */
+  static String getDescription(FeatureType feature)
+  {
+    String orig = feature.getOriginal();
+    List<String> variants = feature.getVariation();
+    StringBuilder sb = new StringBuilder();
+
+    /*
+     * append variant in standard format if present
+     * e.g. p.Arg59Lys
+     * multiple variants are split over lines using <br>
+     */
+    boolean asHtml = false;
+    if (orig != null && !orig.isEmpty() && variants != null
+            && !variants.isEmpty())
+    {
+      int p = 0;
+      for (String var : variants)
+      {
+        // TODO proper HGVS nomenclature for delins structural variations
+        // http://varnomen.hgvs.org/recommendations/protein/variant/delins/
+        // for now we are pragmatic - any orig/variant sequence longer than
+        // three characters is shown with single-character notation rather than
+        // three-letter notation
+        sb.append("p.");
+        if (orig.length() < 4)
+        {
+          for (int c = 0, clen = orig.length(); c < clen; c++)
+          {
+            char origchar = orig.charAt(c);
+            String orig3 = ResidueProperties.aa2Triplet.get("" + origchar);
+            sb.append(orig3 == null ? origchar
+                    : StringUtils.toSentenceCase(orig3));
+          }
+        }
+        else
+        {
+          sb.append(orig);
+        }
+
+        LocationType location = feature.getLocation();
+        PositionType start = location.getPosition() == null
+                ? location.getBegin()
+                : location.getPosition();
+        sb.append(Integer.toString(start.getPosition().intValue()));
+
+        if (var.length() < 4)
+        {
+          for (int c = 0, clen = var.length(); c < clen; c++)
+          {
+            char varchar = var.charAt(c);
+            String var3 = ResidueProperties.aa2Triplet.get("" + varchar);
+
+            sb.append(var3 != null ? StringUtils.toSentenceCase(var3)
+                    : "" + varchar);
+          }
+        }
+        else
+        {
+          sb.append(var);
+        }
+        if (++p != variants.size())
+        {
+          sb.append("<br/>&nbsp;&nbsp;");
+          asHtml = true;
+        }
+        else
+        {
+          sb.append(" ");
+        }
+      }
+    }
+    String description = feature.getDescription();
+    if (description != null)
+    {
+      sb.append(description);
+    }
+    if (asHtml)
+    {
+      sb.insert(0, "<html>");
+      sb.append("</html>");
+    }
+
+    return sb.toString();
+  }
+
+  /**
+   * A helper method that searches the list of properties for one with the given
+   * key, and if found returns the property value, else returns null
+   * 
+   * @param properties
+   * @param key
+   * @return
+   */
+  static String getProperty(List<PropertyType> properties, String key)
+  {
+    String value = null;
+    if (properties != null)
+    {
+      for (PropertyType prop : properties)
+      {
+        if (key.equals(prop.getType()))
+        {
+          value = prop.getValue();
+          break;
+        }
+      }
+    }
+    return value;
+  }
+
+  /**
+   * Extracts xml element entry/protein/recommendedName/fullName
+   * 
+   * @param entry
+   * @return
+   */
+  static String getUniprotEntryDescription(Entry entry)
+  {
+    String desc = "";
+    if (entry.getProtein() != null
+            && entry.getProtein().getRecommendedName() != null)
+    {
+      // fullName is mandatory if recommendedName is present
+      desc = entry.getProtein().getRecommendedName().getFullName()
+              .getValue();
+    }
+    return desc;
+  }
+
+  /**
+   * Constructs a sequence id by concatenating all entry/name elements with '|'
+   * separator
+   * 
+   * @param entry
+   * @return
+   */
+  static String getUniprotEntryId(Entry entry)
+  {
+    StringBuilder name = new StringBuilder(32);
+    for (String n : entry.getName())
+    {
+      if (name.length() > 0)
+      {
+        name.append(BAR_DELIMITER);
+      }
+      name.append(n);
+    }
+    return name.toString();
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
+   */
+  @Override
+  public boolean isValidReference(String accession)
+  {
+    // TODO: make the following a standard validator
+    return (accession == null || accession.length() < 2) ? false
+            : getAccessionValidator().search(accession);
+  }
+
+  /**
+   * return LDHA_CHICK uniprot entry
+   */
+  @Override
+  public String getTestQuery()
+  {
+    return "P00340";
+  }
+
+  @Override
+  public String getDbName()
+  {
+    return "Uniprot"; // getDbSource();
+  }
+
+  @Override
+  public int getTier()
+  {
+    return 0;
+  }
+
+  /**
+   * Reads the reply to the EBI Fetch Uniprot data query, unmarshals it to an
+   * Uniprot object, and returns the enclosed Entry objects, or null on any
+   * failure
+   * 
+   * @param is
+   * @return
+   */
+  public List<Entry> getUniprotEntries(InputStream is)
+  {
+    List<Entry> entries = null;
+    try
+    {
+      JAXBContext jc = JAXBContext
+              .newInstance("jalview.xml.binding.uniprot");
+      XMLStreamReader streamReader = XMLInputFactory.newInstance()
+              .createXMLStreamReader(is);
+      javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
+      JAXBElement<jalview.xml.binding.uniprot.Uniprot> uniprotElement = 
+                 um.unmarshal(streamReader, jalview.xml.binding.uniprot.Uniprot.class);
+      jalview.xml.binding.uniprot.Uniprot uniprot = uniprotElement.getValue();
+      
+      if (uniprot != null && !uniprot.getEntry().isEmpty())
+      {
+        entries = uniprot.getEntry();
+      }
+    } catch (JAXBException | XMLStreamException
+            | FactoryConfigurationError e)
+    {
+      e.printStackTrace();
+    }
+    return entries;
+  }
+}
index 224a712..0b4dd92 100644 (file)
@@ -69,7 +69,7 @@ public class PDBFTSPanelTest
     String expectedString = "1xyz OR text:2xyz OR text:3xyz";
     String outcome = PDBFTSPanel.decodeSearchTerm("1xyz:A;2xyz;3xyz",
             "text");
-    // System.out.println("1 >>>>>>>>>>> " + outcome);
+    System.out.println("1 >>>>>>>>>>> " + outcome);
     assertEquals(expectedString, outcome);
 
     expectedString = "1xyz";
@@ -124,5 +124,13 @@ public class PDBFTSPanelTest
     assertTrue(!mainFrame.getTitle().equalsIgnoreCase(
             "PDB Sequence Fetcher"));
   }
+  
+  @Test
+  public void getFTSframeTitleTest() {
+    PDBFTSPanel searchPanel = new PDBFTSPanel(null);
+    String outcome = searchPanel.getFTSFrameTitle();
+    //System.out.println("FTS Frame title :" + outcome);
+    assertEquals(outcome, "PDB Sequence Fetcher");
+  }
 
 }
index bbd45aa..39ae75d 100644 (file)
@@ -93,6 +93,8 @@ public class PDBFTSRestClientTest
     {
       e1.printStackTrace();
     }
+    System.out.println("wantedFields >>" + wantedFields);
+
 
     FTSRestRequest request = new FTSRestRequest();
     request.setAllowEmptySeq(false);
@@ -196,6 +198,7 @@ public class PDBFTSRestClientTest
   @Test(groups = { "External" }, expectedExceptions = Exception.class)
   public void testForExpectedRuntimeException() throws Exception
   {
+    // JBPNote: looks like this test fails for no good reason - what exception was supposed to be raised ?
     List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
     wantedFields.add(PDBFTSRestClient.getInstance()
             .getDataColumnByNameOrCode("pdb_id"));
@@ -246,6 +249,7 @@ public class PDBFTSRestClientTest
     assertTrue(response.getSearchSummary() != null);
     assertTrue(response.getNumberOfItemsFound() == 931);
     assertTrue(response.getSearchSummary().size() == 14);
+    System.out.println("Search summary : " + response.getSearchSummary());
   }
 
   @Test(groups = { "Functional" })
diff --git a/test/jalview/fts/threedbeacons/.gitignore b/test/jalview/fts/threedbeacons/.gitignore
new file mode 100644 (file)
index 0000000..084aa65
--- /dev/null
@@ -0,0 +1,2 @@
+/tdbJson.java
+/tdbresttest2.java
diff --git a/test/jalview/fts/threedbeacons/TDBeaconsFTSRestClientTest.java b/test/jalview/fts/threedbeacons/TDBeaconsFTSRestClientTest.java
new file mode 100644 (file)
index 0000000..9a27cf3
--- /dev/null
@@ -0,0 +1,323 @@
+package jalview.fts.threedbeacons;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
+import jalview.gui.JvOptionPane;
+
+public class TDBeaconsFTSRestClientTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+  
+  private FTSRestClient ftsRestClient;
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception
+  {
+    ftsRestClient = new FTSRestClient()
+    {
+
+      @Override
+      public String getColumnDataConfigFileName()
+      {
+        return "/fts/tdbeacons_data_columns.txt";
+      }
+
+      @Override
+      public FTSRestResponse executeRequest(FTSRestRequest ftsRequest)
+              throws Exception
+      {
+        return null;
+      }
+    };
+  }
+
+  @AfterMethod(alwaysRun = true)
+  public void tearDown() throws Exception
+  {
+  }
+  
+  @Test
+  public void getAllDefaulDisplayedDataColumns()
+  {     
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    Assert.assertNotNull(ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns());
+    System.out.println(ftsRestClient.getAllDefaultDisplayedFTSDataColumns());
+    Assert.assertTrue(!ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
+            .isEmpty());
+    Assert.assertEquals(ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns().size(), 11);
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getPrimaryKeyColumIndexTest()
+  {
+    Collection<FTSDataColumnI> wantedFields = ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns();
+    int foundIndex = -1;
+    try
+    {
+      Assert.assertEquals(foundIndex, -1);
+      foundIndex = ftsRestClient.getPrimaryKeyColumIndex(wantedFields,
+              false);
+      Assert.assertEquals(foundIndex, 10);
+      foundIndex = ftsRestClient
+              .getPrimaryKeyColumIndex(wantedFields, true);
+      Assert.assertEquals(foundIndex, 11);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getDataColumnsFieldsAsCommaDelimitedString()
+  {
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    Collection<FTSDataColumnI> wantedFields = ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns();
+    String actual = ftsRestClient
+            .getDataColumnsFieldsAsCommaDelimitedString(wantedFields);
+    Assert.assertEquals(actual,
+            "model_identifier,provider,model_category,uniprot_start,uniprot_end,resolution,qmean_avg_local_score,coverage,created,entry_name,model_url");
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getAllFTSDataColumns()
+  {
+    Collection<FTSDataColumnI> allFields = ftsRestClient
+            .getAllFTSDataColumns();
+    Assert.assertNotNull(allFields);
+    //System.out.println(allFields.size());
+    Assert.assertEquals(allFields.size(), 15);
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getSearchableDataColumns()
+  {     
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    Collection<FTSDataColumnI> searchableFields = ftsRestClient
+            .getSearchableDataColumns();
+    Assert.assertNotNull(searchableFields);
+    //System.out.println(searchableFields.size());
+    Assert.assertEquals(searchableFields.size(), 1); //only 1: uniprot accession
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getPrimaryKeyColumn()
+  { 
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    FTSDataColumnI expectedPKColumn;
+    try
+    {
+      expectedPKColumn = ftsRestClient
+              .getDataColumnByNameOrCode("Url");
+      Assert.assertNotNull(ftsRestClient.getPrimaryKeyColumn());
+      Assert.assertEquals(ftsRestClient.getPrimaryKeyColumn(),
+              expectedPKColumn);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getDataColumnByNameOrCode()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("uniprot_accession");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getName(), "UniProt Accession");
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getDataColumnGroupById()
+  {
+    FTSDataColumnGroupI foundDataColGroup;
+    try
+    {
+      foundDataColGroup = ftsRestClient.getDataColumnGroupById("g2");
+      Assert.assertNotNull(foundDataColGroup);
+      Assert.assertEquals(foundDataColGroup.getName(), "Quality");
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getDefaultResponsePageSize()
+  {
+    int defaultResSize = ftsRestClient.getDefaultResponsePageSize();
+    Assert.assertEquals(defaultResSize, 100); //why 100 or 500 ? pdb is 100, uniprot 500
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getColumnMinWidthTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("uniprot_accession");
+      Assert.assertNotNull(foundDataCol);
+      int actualColMinWidth = foundDataCol.getMinWidth();
+      Assert.assertEquals(actualColMinWidth, 50);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+  // could add test for MaxWidth & PreferedWith
+  
+  @Test(groups = { "Functional" })
+  public void getColumnClassTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("uniprot_accession");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              String.class);
+      foundDataCol = ftsRestClient.getDataColumnByNameOrCode("id");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              String.class);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+  
+  @Test(groups = { "Functional" })
+  public void coverageForEqualsAndHashFunction()
+  {
+    Set<FTSDataColumnI> uniqueSet = new HashSet<FTSDataColumnI>();
+    Collection<FTSDataColumnI> searchableCols = ftsRestClient
+            .getSearchableDataColumns();
+    System.out.println(searchableCols);
+    for (FTSDataColumnI foundCol : searchableCols)
+    {
+      System.out.println(foundCol.toString());
+      uniqueSet.add(foundCol);
+      uniqueSet.add(foundCol);
+    }
+    Assert.assertTrue(!uniqueSet.isEmpty());
+    //Assert.assertEquals(uniqueSet.size(), 22); -> 1 or 2 currently for 3DB
+  }
+  
+  @Test(groups = { "Functional" })
+  public void getTDBIdColumIndexTest()
+  {
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("Model id"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_accession"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("entry name"));
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    try
+    {
+      assertEquals(4, TDBeaconsFTSRestClient.getInstance()
+              .getPrimaryKeyColumIndex(wantedFields, true));
+//      assertEquals(3, TDBeaconsFTSRestClient.getInstance()
+//              .getPrimaryKeyColumIndex(wantedFields, true));
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+  
+
+  @Test(groups = { "External", "Network" })  
+  public void executeRequestTest()
+  {
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("Model Id"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("model_url"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("provider"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("model_category"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("qmean_avg_local_score"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_start"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_end"));
+    } catch (Exception e1)
+    {
+      e1.printStackTrace();
+    }
+    System.out.println("wantedFields >>" + wantedFields);
+
+    FTSRestRequest request = new FTSRestRequest();
+    request.setResponseSize(100);
+    request.setFieldToSearchBy("");
+    request.setSearchTerm("P01318.json");
+    request.setWantedFields(wantedFields);
+    System.out.println("request : " + request.getFieldToSearchBy());
+    //System.out.println(request.toString());
+
+    FTSRestResponse response;
+    try
+    {
+      response = TDBeaconsFTSRestClient.getInstance().executeRequest(request);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Couldn't execute webservice call!");
+      return;
+    }
+    assertTrue(response.getSearchSummary() != null);
+    assertTrue(response.getNumberOfItemsFound() > 3); //4 atm
+    System.out.println("Search summary : \n" + response.getSearchSummary());
+    //System.out.println(response.getSearchSummary().size());
+  }
+}
diff --git a/test/jalview/fts/threedbeacons/TDBeaconsPanelTest.java b/test/jalview/fts/threedbeacons/TDBeaconsPanelTest.java
new file mode 100644 (file)
index 0000000..dec33e3
--- /dev/null
@@ -0,0 +1,68 @@
+package jalview.fts.threedbeacons;
+
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.fts.service.pdb.PDBFTSPanel;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSPanel;
+import jalview.gui.JvOptionPane;
+
+import javax.swing.JComboBox;
+import javax.swing.JInternalFrame;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import junit.extensions.PA;
+
+
+public class TDBeaconsPanelTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception
+  {
+  }
+
+  @AfterMethod(alwaysRun = true)
+  public void tearDown() throws Exception
+  {
+  }
+
+  @Test(groups = { "Functional" })
+  public void populateCmbSearchTargetOptionsTest()
+  {
+    TDBeaconsFTSPanel searchPanel = new TDBeaconsFTSPanel(null);
+    assertTrue(searchPanel.getCmbSearchTarget().getItemCount() > 0);
+    searchPanel.populateCmbSearchTargetOptions();
+  }
+  
+  @Test
+  public void getFTSframeTitleTest() {
+    TDBeaconsFTSPanel searchPanel = new TDBeaconsFTSPanel(null);
+    System.out.println(searchPanel.getFTSFrameTitle());
+  }
+  
+  @Test
+  public void testgetUNIPROTid() {
+    String outcome = TDBeaconsFTSPanel.decodeSearchTerm("P01308");
+    System.out.println(outcome);
+  }
+//  
+//  @Test
+//  public void queryTest() {
+//    int outcome = TDBeaconsFTSPanel.executeParse("P01308");
+//    //System.out.println("query outcome :" + outcome);
+//    int expected_length = 110;
+//    assertEquals(outcome, expected_length);
+//  }
+}
index 073bde8..31f5f8b 100644 (file)
@@ -30,6 +30,8 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.fts.api.FTSData;
+import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
+import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.jbgui.GStructureChooser.FilterOption;
 import jalview.ws.params.InvalidArgumentException;
 
@@ -83,19 +85,22 @@ public class StructureChooserTest
     seq = null;
   }
 
+  @SuppressWarnings("deprecation")
   @Test(groups = { "Functional" })
   public void buildQueryTest()
   {
-    String query = StructureChooser.buildQuery(seq);
-    assertEquals("pdb_id:1tim", query);
     System.out.println("seq >>>> " + seq);
+    StructureChooserQuerySource scquery = StructureChooserQuerySource.getPDBfts();
+    String query = scquery.buildQuery(seq);
+    assertEquals("pdb_id:1tim", query);
     seq.getAllPDBEntries().clear();
-    query = StructureChooser.buildQuery(seq);
+    query = scquery.buildQuery(seq);
     assertEquals(
             "text:XYZ_1 OR text:XYZ_2 OR text:XYZ_3 OR text:XYZ_4 OR text:4kqy",
             query);
-       seq.setDBRefs(null);
-    query = StructureChooser.buildQuery(seq);
+    seq.setDBRefs(null);
+    query = scquery.buildQuery(seq);
+    System.out.println(query);
     assertEquals("text:4kqy", query);
 
     DBRefEntry uniprotDBRef = new DBRefEntry();
@@ -114,7 +119,10 @@ public class StructureChooserTest
       dbRef.setAccessionId("XYZ_" + x);
       seq.addDBRef(dbRef);
     }
-    query = StructureChooser.buildQuery(seq);
+    System.out.println("");
+    System.out.println(seq.getDBRefs());
+    System.out.println(query);
+    query = scquery.buildQuery(seq);
     assertEquals(
             "uniprot_accession:P12345 OR uniprot_id:P12345 OR pdb_id:1xyz",
             query);
@@ -159,17 +167,17 @@ public class StructureChooserTest
   public void sanitizeSeqNameTest()
   {
     String name = "ab_cdEF|fwxyz012349";
-    assertEquals(name, StructureChooser.sanitizeSeqName(name));
+    assertEquals(name, PDBStructureChooserQuerySource.sanitizeSeqName(name));
 
     // remove a [nn] substring
     name = "abcde12[345]fg";
-    assertEquals("abcde12fg", StructureChooser.sanitizeSeqName(name));
+    assertEquals("abcde12fg", PDBStructureChooserQuerySource.sanitizeSeqName(name));
 
     // remove characters other than a-zA-Z0-9 | or _
     name = "ab[cd],.\t£$*!- \\\"@:e";
-    assertEquals("abcde", StructureChooser.sanitizeSeqName(name));
+    assertEquals("abcde", PDBStructureChooserQuerySource.sanitizeSeqName(name));
 
     name = "abcde12[345a]fg";
-    assertEquals("abcde12345afg", StructureChooser.sanitizeSeqName(name));
+    assertEquals("abcde12345afg", PDBStructureChooserQuerySource.sanitizeSeqName(name));
   }
 }