1 package jalview.gui.structurechooser;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.HashSet;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.Locale;
14 import javax.swing.JTable;
16 import jalview.datamodel.DBRefEntry;
17 import jalview.datamodel.DBRefSource;
18 import jalview.datamodel.PDBEntry;
19 import jalview.datamodel.SequenceI;
20 import jalview.fts.api.FTSData;
21 import jalview.fts.api.FTSDataColumnI;
22 import jalview.fts.api.FTSRestClientI;
23 import jalview.fts.core.FTSDataColumnPreferences;
24 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
25 import jalview.fts.core.FTSRestRequest;
26 import jalview.fts.core.FTSRestResponse;
27 import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
28 import jalview.jbgui.FilterOption;
29 import jalview.util.MessageManager;
32 * logic for querying the 3DBeacons API for structures of sequences
36 public class ThreeDBStructureChooserQuerySource
37 extends StructureChooserQuerySource
40 private Set<String> tdBeaconsFilters = null, defaultFilters = null;
42 public static final String FILTER_TDBEACONS_COVERAGE = "3d_beacons_coverage";
44 public static final String FILTER_FIRST_BEST_COVERAGE = "3d_beacons_first_best_coverage";
46 private static final String FILTER_SOURCE_PREFIX = "only_";
48 private static int MAX_QLENGTH = 7820;
50 protected FTSRestRequest lastTdbRequest;
52 protected FTSRestClientI tdbRestClient;
54 private FTSRestRequest lastPdbRequest;
56 public ThreeDBStructureChooserQuerySource()
58 defaultFilters = new LinkedHashSet<String>();
59 defaultFilters.add(FILTER_TDBEACONS_COVERAGE);
60 defaultFilters.add(FILTER_FIRST_BEST_COVERAGE);
62 tdbRestClient = TDBeaconsFTSRestClient.getInstance();
63 docFieldPrefs = new FTSDataColumnPreferences(
64 PreferenceSource.STRUCTURE_CHOOSER,
65 TDBeaconsFTSRestClient.getInstance());
69 * Builds a query string for a given sequences using its DBRef entries 3d
70 * Beacons is only useful for uniprot IDs
73 * the sequences to build a query for
74 * @return the built query string
77 public String buildQuery(SequenceI seq)
79 boolean isPDBRefsFound = false;
80 boolean isUniProtRefsFound = false;
81 StringBuilder queryBuilder = new StringBuilder();
82 Set<String> seqRefs = new LinkedHashSet<>();
85 * note PDBs as DBRefEntry so they are not duplicated in query
87 Set<String> pdbids = new HashSet<>();
89 List<DBRefEntry> refs = seq.getDBRefs();
90 if (refs != null && refs.size() != 0)
92 for (int ib = 0, nb = refs.size(); ib < nb; ib++)
94 DBRefEntry dbRef = refs.get(ib);
95 if (isValidSeqName(getDBRefId(dbRef))
96 && queryBuilder.length() < MAX_QLENGTH)
98 if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT)
99 && dbRef.isCanonical())
101 // TODO: pick best Uniprot accession
102 isUniProtRefsFound = true;
103 return getDBRefId(dbRef);
113 * Ensures sequence ref names are not less than 3 characters and does not
114 * contain a database name
119 static boolean isValidSeqName(String seqName)
121 // System.out.println("seqName : " + seqName);
122 String ignoreList = "pdb,uniprot,swiss-prot";
123 if (seqName.length() < 3)
127 if (seqName.contains(":"))
131 seqName = seqName.toLowerCase();
132 for (String ignoredEntry : ignoreList.split(","))
134 if (seqName.contains(ignoredEntry))
142 static String getDBRefId(DBRefEntry dbRef)
144 String ref = dbRef.getAccessionId().replaceAll("GO:", "");
149 * FTSRestClient specific query builder to recover associated structure data
150 * records for a sequence
153 * - seq to generate a query for
154 * @param wantedFields
155 * - fields to retrieve
156 * @param selectedFilterOpt
157 * - criterion for ranking results (e.g. resolution)
159 * - sort ascending or descending
163 public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
164 Collection<FTSDataColumnI> wantedFields,
165 FilterOption selectedFilterOpt, boolean b) throws Exception
167 FTSRestResponse resultList;
168 if (selectedFilterOpt!=null && tdBeaconsFilter(selectedFilterOpt.getValue()))
170 FTSRestRequest tdbRequest = getTDBeaconsRequest(seq, wantedFields);
171 resultList = tdbRestClient.executeRequest(tdbRequest);
173 lastTdbRequest = tdbRequest;
175 // Query the PDB and add additional metadata
176 FTSRestResponse pdbResponse = fetchStructuresMetaDataFor(
177 getPDBQuerySource(), resultList);
178 FTSRestResponse joinedResp = joinResponses(resultList, pdbResponse);
181 // use the PDBFTS directly
182 resultList = getPDBQuerySource().fetchStructuresMetaData(seq,
183 wantedFields, selectedFilterOpt, b);
184 lastTdbRequest = getPDBQuerySource().lastPdbRequest;
185 lastPdbRequest = lastTdbRequest; // both queries the same - indicates we
191 PDBStructureChooserQuerySource pdbQuerySource = null;
193 private PDBStructureChooserQuerySource getPDBQuerySource()
195 if (pdbQuerySource == null)
197 pdbQuerySource = new PDBStructureChooserQuerySource();
199 return pdbQuerySource;
202 private FTSRestRequest getTDBeaconsRequest(SequenceI seq,
203 Collection<FTSDataColumnI> wantedFields)
205 FTSRestRequest pdbRequest = new FTSRestRequest();
206 pdbRequest.setAllowEmptySeq(false);
207 pdbRequest.setResponseSize(500);
208 pdbRequest.setWantedFields(wantedFields);
209 String query = buildQuery(seq);
214 pdbRequest.setSearchTerm(query + ".json");
215 pdbRequest.setAssociatedSequence(seq);
220 public List<FilterOption> getAvailableFilterOptions(String VIEWS_FILTER)
222 List<FilterOption> filters = getPDBQuerySource()
223 .getAvailableFilterOptions(VIEWS_FILTER);
224 tdBeaconsFilters = new LinkedHashSet<String>();
225 tdBeaconsFilters.addAll(defaultFilters);
226 filters.add(0, new FilterOption("Best 3D-Beacons Coverage",
227 FILTER_FIRST_BEST_COVERAGE, VIEWS_FILTER, false, this));
228 filters.add(1, new FilterOption("Multiple 3D-Beacons Coverage",
229 FILTER_TDBEACONS_COVERAGE, VIEWS_FILTER, true, this));
235 public void updateAvailableFilterOptions(String VIEWS_FILTER,
236 List<FilterOption> xtantOptions, Collection<FTSData> tdbEntries)
238 if (tdbEntries !=null && lastTdbRequest != null)
240 int prov_idx = lastTdbRequest.getFieldIndex("Provider");
242 for (FTSData row : tdbEntries)
244 String provider = (String) row.getSummaryData()[prov_idx];
245 FilterOption providerOpt = new FilterOption("3DB Provider - " + provider,
246 FILTER_SOURCE_PREFIX + provider, VIEWS_FILTER,
248 if (!xtantOptions.contains(providerOpt))
252 tdBeaconsFilters.add(FILTER_SOURCE_PREFIX+provider);
260 private boolean tdBeaconsFilter(String fieldToFilterBy)
262 return tdBeaconsFilters != null
263 && tdBeaconsFilters.contains(fieldToFilterBy);
266 private String remove_prefix(String fieldToFilterBy)
268 if (tdBeaconsFilters != null
269 && tdBeaconsFilters.contains(fieldToFilterBy)
270 && !defaultFilters.contains(fieldToFilterBy))
272 return fieldToFilterBy.substring(FILTER_SOURCE_PREFIX.length());
281 public boolean needsRefetch(FilterOption selectedFilterOpt)
283 return selectedFilterOpt==null || !tdBeaconsFilter(selectedFilterOpt.getValue())
284 && lastPdbRequest != lastTdbRequest;
288 * FTSRestClient specific query builder to pick top ranked entry from a
289 * fetchStructuresMetaData query
292 * - seq to generate a query for
293 * @param wantedFields
294 * - fields to retrieve
295 * @param selectedFilterOpt
296 * - criterion for ranking results (e.g. resolution)
298 * - sort ascending or descending
302 public FTSRestResponse selectFirstRankedQuery(SequenceI seq,
303 Collection<FTSData> collectedResults,
304 Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
305 boolean b) throws Exception
307 if (fieldToFilterBy!=null && tdBeaconsFilter(fieldToFilterBy))
309 TDBResultAnalyser analyser = new TDBResultAnalyser(seq,
310 collectedResults, lastTdbRequest, fieldToFilterBy,
311 remove_prefix(fieldToFilterBy));
313 FTSRestResponse resultList = new FTSRestResponse();
315 List<FTSData> filteredResponse = analyser.getFilteredResponse();
317 List<FTSData> selectedStructures = analyser
318 .selectStructures(filteredResponse);
319 resultList.setNumberOfItemsFound(selectedStructures.size());
320 resultList.setSearchSummary(selectedStructures);
323 // Fall back to PDBe rankings
324 return getPDBQuerySource().selectFirstRankedQuery(seq, collectedResults,
325 wantedFields, fieldToFilterBy, b);
329 public PDBEntry[] collectSelectedRows(JTable restable, int[] selectedRows,
330 List<SequenceI> selectedSeqsToView)
332 int refSeqColIndex = restable.getColumn("Ref Sequence").getModelIndex();
334 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
336 int idColumnIndex = restable.getColumn("Model id").getModelIndex();
337 int urlColumnIndex = restable.getColumn("Url").getModelIndex();
338 int typeColumnIndex = restable.getColumn("Provider").getModelIndex();
339 int categoryColumnIndex = restable.getColumn("Model Category")
341 final int up_start_idx = restable.getColumn("Uniprot Start")
343 final int up_end_idx = restable.getColumn("Uniprot End")
348 Integer[] sellist = new Integer[selectedRows.length];
349 for (Integer row : selectedRows)
353 // Sort rows by coverage
354 Arrays.sort(sellist, new Comparator<Integer>()
357 public int compare(Integer o1, Integer o2)
359 int o1_xt = ((Integer) restable.getValueAt(o1, up_end_idx))
360 - (Integer) restable.getValueAt(o1, up_start_idx);
361 int o2_xt = ((Integer) restable.getValueAt(o2, up_end_idx))
362 - (Integer) restable.getValueAt(o2, up_start_idx);
363 return o2_xt - o1_xt;
367 for (int row : sellist)
369 // unique id - could be a horrible hash
371 String pdbIdStr = restable.getValueAt(row, idColumnIndex).toString();
372 String urlStr = restable.getValueAt(row, urlColumnIndex).toString();
373 String typeColumn = restable.getValueAt(row, typeColumnIndex)
375 SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
377 selectedSeqsToView.add(selectedSeq);
378 PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
379 if (pdbEntry == null)
381 pdbEntry = getFindEntry(pdbIdStr, selectedSeq.getAllPDBEntries());
384 if (pdbEntry == null)
386 pdbEntry = new PDBEntry();
387 pdbEntry.setId(pdbIdStr);
388 boolean hasCif = urlStr.toLowerCase(Locale.ENGLISH).endsWith("cif");
389 boolean probablyPdb = urlStr.toLowerCase(Locale.ENGLISH).contains("pdb");
390 pdbEntry.setType(hasCif ? PDBEntry.Type.MMCIF : probablyPdb ? PDBEntry.Type.PDB : PDBEntry.Type.FILE);
391 if (!"PDBe".equalsIgnoreCase(typeColumn))
393 pdbEntry.setRetrievalUrl(urlStr);
395 selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
397 pdbEntriesToView[count++] = pdbEntry;
399 return pdbEntriesToView;
403 protected FTSRestRequest getLastFTSRequest()
405 return lastTdbRequest;
409 * generate a query for PDBFTS to retrieve structure metadata
411 * @param ftsRestRequest
416 public String buildPDBFTSQueryFor(FTSRestResponse upResponse)
418 List<String> pdbIds = new ArrayList<String>();
419 int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
420 int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
421 for (FTSData row : upResponse.getSearchSummary())
423 String id = (String) row.getSummaryData()[idx_modelId];
424 String provider = (String) row.getSummaryData()[idx_provider];
425 if ("PDBe".equalsIgnoreCase(provider))
430 return String.join(" OR ", pdbIds).toString();
434 * query PDBe for structure metadata
438 * @return FTSRestResponse via PDBStructureChooserQuerySource
440 public FTSRestResponse fetchStructuresMetaDataFor(
441 PDBStructureChooserQuerySource pdbquery,
442 FTSRestResponse upResponse) throws Exception
445 String pdb_Query = buildPDBFTSQueryFor(upResponse);
446 if (pdb_Query.length()==0)
450 FTSRestResponse resultList;
451 FTSRestRequest pdbRequest = new FTSRestRequest();
452 pdbRequest.setAllowEmptySeq(false);
453 pdbRequest.setResponseSize(500);
454 pdbRequest.setFieldToSearchBy("(");
455 // pdbRequest.setFieldToSortBy("pdb_id");
456 pdbRequest.setWantedFields(
457 pdbquery.getDocFieldPrefs().getStructureSummaryFields());
458 pdbRequest.setSearchTerm(pdb_Query + ")");
460 resultList = pdbquery.executePDBFTSRestRequest(pdbRequest);
462 lastPdbRequest = pdbRequest;
466 public FTSRestResponse joinResponses(FTSRestResponse upResponse,
467 FTSRestResponse pdbResponse)
469 int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
471 int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
472 int pdbIdx = lastPdbRequest.getFieldIndex("PDB Id");
473 int pdbTitle_idx = lastPdbRequest.getFieldIndex("Title");
474 int tdbTitle_idx = getLastFTSRequest().getFieldIndex("Title");
476 List<FTSData> joinedRows = new ArrayList<FTSData>();
477 for (final FTSData row : upResponse.getSearchSummary())
479 String id = (String) row.getSummaryData()[idx_modelId];
480 String provider = (String) row.getSummaryData()[idx_provider];
481 if ("PDBe".equalsIgnoreCase(provider))
483 for (final FTSData pdbrow : pdbResponse.getSearchSummary())
485 String pdbid = (String) pdbrow.getSummaryData()[pdbIdx];
486 if (id.equalsIgnoreCase(pdbid))
488 row.getSummaryData()[tdbTitle_idx] = pdbrow
489 .getSummaryData()[pdbTitle_idx];
495 row.getSummaryData()[tdbTitle_idx] = "Model from TDB";