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;
13 import javax.swing.JTable;
15 import jalview.datamodel.DBRefEntry;
16 import jalview.datamodel.DBRefSource;
17 import jalview.datamodel.PDBEntry;
18 import jalview.datamodel.SequenceI;
19 import jalview.fts.api.FTSData;
20 import jalview.fts.api.FTSDataColumnI;
21 import jalview.fts.api.FTSRestClientI;
22 import jalview.fts.core.FTSDataColumnPreferences;
23 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
24 import jalview.fts.core.FTSRestRequest;
25 import jalview.fts.core.FTSRestResponse;
26 import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
27 import jalview.jbgui.FilterOption;
28 import jalview.util.MessageManager;
31 * logic for querying the 3DBeacons API for structures of sequences
35 public class ThreeDBStructureChooserQuerySource
36 extends StructureChooserQuerySource
39 private Set<String> tdBeaconsFilters = null, defaultFilters = null;
41 public static final String FILTER_TDBEACONS_COVERAGE = "3d_beacons_coverage";
43 public static final String FILTER_FIRST_BEST_COVERAGE = "3d_beacons_first_best_coverage";
45 private static final String FILTER_SOURCE_PREFIX = "only_";
47 private static int MAX_QLENGTH = 7820;
49 protected FTSRestRequest lastTdbRequest;
51 protected FTSRestClientI tdbRestClient;
53 private FTSRestRequest lastPdbRequest;
55 public ThreeDBStructureChooserQuerySource()
57 defaultFilters = new LinkedHashSet<String>();
58 defaultFilters.add(FILTER_TDBEACONS_COVERAGE);
59 defaultFilters.add(FILTER_FIRST_BEST_COVERAGE);
61 tdbRestClient = TDBeaconsFTSRestClient.getInstance();
62 docFieldPrefs = new FTSDataColumnPreferences(
63 PreferenceSource.STRUCTURE_CHOOSER,
64 TDBeaconsFTSRestClient.getInstance());
68 * Builds a query string for a given sequences using its DBRef entries 3d
69 * Beacons is only useful for uniprot IDs
72 * the sequences to build a query for
73 * @return the built query string
76 public String buildQuery(SequenceI seq)
78 boolean isPDBRefsFound = false;
79 boolean isUniProtRefsFound = false;
80 StringBuilder queryBuilder = new StringBuilder();
81 Set<String> seqRefs = new LinkedHashSet<>();
84 * note PDBs as DBRefEntry so they are not duplicated in query
86 Set<String> pdbids = new HashSet<>();
88 List<DBRefEntry> refs = seq.getDBRefs();
89 if (refs != null && refs.size() != 0)
91 for (int ib = 0, nb = refs.size(); ib < nb; ib++)
93 DBRefEntry dbRef = refs.get(ib);
94 if (isValidSeqName(getDBRefId(dbRef))
95 && queryBuilder.length() < MAX_QLENGTH)
97 if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT)
98 && dbRef.isCanonical())
100 // TODO: pick best Uniprot accession
101 isUniProtRefsFound = true;
102 return getDBRefId(dbRef);
112 * Ensures sequence ref names are not less than 3 characters and does not
113 * contain a database name
118 static boolean isValidSeqName(String seqName)
120 // System.out.println("seqName : " + seqName);
121 String ignoreList = "pdb,uniprot,swiss-prot";
122 if (seqName.length() < 3)
126 if (seqName.contains(":"))
130 seqName = seqName.toLowerCase();
131 for (String ignoredEntry : ignoreList.split(","))
133 if (seqName.contains(ignoredEntry))
141 static String getDBRefId(DBRefEntry dbRef)
143 String ref = dbRef.getAccessionId().replaceAll("GO:", "");
148 * FTSRestClient specific query builder to recover associated structure data
149 * records for a sequence
152 * - seq to generate a query for
153 * @param wantedFields
154 * - fields to retrieve
155 * @param selectedFilterOpt
156 * - criterion for ranking results (e.g. resolution)
158 * - sort ascending or descending
162 public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
163 Collection<FTSDataColumnI> wantedFields,
164 FilterOption selectedFilterOpt, boolean b) throws Exception
166 FTSRestResponse resultList;
167 if (selectedFilterOpt!=null && tdBeaconsFilter(selectedFilterOpt.getValue()))
169 FTSRestRequest tdbRequest = getTDBeaconsRequest(seq, wantedFields);
170 resultList = tdbRestClient.executeRequest(tdbRequest);
172 lastTdbRequest = tdbRequest;
174 // Query the PDB and add additional metadata
175 FTSRestResponse pdbResponse = fetchStructuresMetaDataFor(
176 getPDBQuerySource(), resultList);
177 FTSRestResponse joinedResp = joinResponses(resultList, pdbResponse);
180 // use the PDBFTS directly
181 resultList = getPDBQuerySource().fetchStructuresMetaData(seq,
182 wantedFields, selectedFilterOpt, b);
183 lastTdbRequest = getPDBQuerySource().lastPdbRequest;
184 lastPdbRequest = lastTdbRequest; // both queries the same - indicates we
190 PDBStructureChooserQuerySource pdbQuerySource = null;
192 private PDBStructureChooserQuerySource getPDBQuerySource()
194 if (pdbQuerySource == null)
196 pdbQuerySource = new PDBStructureChooserQuerySource();
198 return pdbQuerySource;
201 private FTSRestRequest getTDBeaconsRequest(SequenceI seq,
202 Collection<FTSDataColumnI> wantedFields)
204 FTSRestRequest pdbRequest = new FTSRestRequest();
205 pdbRequest.setAllowEmptySeq(false);
206 pdbRequest.setResponseSize(500);
207 pdbRequest.setWantedFields(wantedFields);
208 String query = buildQuery(seq);
213 pdbRequest.setSearchTerm(query + ".json");
214 pdbRequest.setAssociatedSequence(seq);
219 public List<FilterOption> getAvailableFilterOptions(String VIEWS_FILTER)
221 List<FilterOption> filters = getPDBQuerySource()
222 .getAvailableFilterOptions(VIEWS_FILTER);
223 tdBeaconsFilters = new LinkedHashSet<String>();
224 tdBeaconsFilters.addAll(defaultFilters);
225 filters.add(0, new FilterOption("Best 3D-Beacons Coverage",
226 FILTER_FIRST_BEST_COVERAGE, VIEWS_FILTER, false, this));
227 filters.add(1, new FilterOption("Multiple 3D-Beacons Coverage",
228 FILTER_TDBEACONS_COVERAGE, VIEWS_FILTER, true, this));
234 public void updateAvailableFilterOptions(String VIEWS_FILTER,
235 List<FilterOption> xtantOptions, Collection<FTSData> tdbEntries)
237 if (tdbEntries !=null && lastTdbRequest != null)
239 int prov_idx = lastTdbRequest.getFieldIndex("Provider");
241 for (FTSData row : tdbEntries)
243 String provider = (String) row.getSummaryData()[prov_idx];
244 FilterOption providerOpt = new FilterOption("3DB Provider - " + provider,
245 FILTER_SOURCE_PREFIX + provider, VIEWS_FILTER,
247 if (!xtantOptions.contains(providerOpt))
251 tdBeaconsFilters.add(FILTER_SOURCE_PREFIX+provider);
259 private boolean tdBeaconsFilter(String fieldToFilterBy)
261 return tdBeaconsFilters != null
262 && tdBeaconsFilters.contains(fieldToFilterBy);
265 private String remove_prefix(String fieldToFilterBy)
267 if (tdBeaconsFilters != null
268 && tdBeaconsFilters.contains(fieldToFilterBy)
269 && !defaultFilters.contains(fieldToFilterBy))
271 return fieldToFilterBy.substring(FILTER_SOURCE_PREFIX.length());
280 public boolean needsRefetch(FilterOption selectedFilterOpt)
282 return selectedFilterOpt==null || !tdBeaconsFilter(selectedFilterOpt.getValue())
283 && lastPdbRequest != lastTdbRequest;
287 * FTSRestClient specific query builder to pick top ranked entry from a
288 * fetchStructuresMetaData query
291 * - seq to generate a query for
292 * @param wantedFields
293 * - fields to retrieve
294 * @param selectedFilterOpt
295 * - criterion for ranking results (e.g. resolution)
297 * - sort ascending or descending
301 public FTSRestResponse selectFirstRankedQuery(SequenceI seq,
302 Collection<FTSData> collectedResults,
303 Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
304 boolean b) throws Exception
306 if (fieldToFilterBy!=null && tdBeaconsFilter(fieldToFilterBy))
308 TDBResultAnalyser analyser = new TDBResultAnalyser(seq,
309 collectedResults, lastTdbRequest, fieldToFilterBy,
310 remove_prefix(fieldToFilterBy));
312 FTSRestResponse resultList = new FTSRestResponse();
314 List<FTSData> filteredResponse = analyser.getFilteredResponse();
316 List<FTSData> selectedStructures = analyser
317 .selectStructures(filteredResponse);
318 resultList.setNumberOfItemsFound(selectedStructures.size());
319 resultList.setSearchSummary(selectedStructures);
322 // Fall back to PDBe rankings
323 return getPDBQuerySource().selectFirstRankedQuery(seq, collectedResults,
324 wantedFields, fieldToFilterBy, b);
328 public PDBEntry[] collectSelectedRows(JTable restable, int[] selectedRows,
329 List<SequenceI> selectedSeqsToView)
331 int refSeqColIndex = restable.getColumn("Ref Sequence").getModelIndex();
333 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
335 int idColumnIndex = restable.getColumn("Model id").getModelIndex();
336 int urlColumnIndex = restable.getColumn("Url").getModelIndex();
337 int typeColumnIndex = restable.getColumn("Provider").getModelIndex();
338 int categoryColumnIndex = restable.getColumn("Model Category")
340 final int up_start_idx = restable.getColumn("Uniprot Start")
342 final int up_end_idx = restable.getColumn("Uniprot End")
347 Integer[] sellist = new Integer[selectedRows.length];
348 for (Integer row : selectedRows)
352 // Sort rows by coverage
353 Arrays.sort(sellist, new Comparator<Integer>()
356 public int compare(Integer o1, Integer o2)
358 int o1_xt = ((Integer) restable.getValueAt(o1, up_end_idx))
359 - (Integer) restable.getValueAt(o1, up_start_idx);
360 int o2_xt = ((Integer) restable.getValueAt(o2, up_end_idx))
361 - (Integer) restable.getValueAt(o2, up_start_idx);
362 return o2_xt - o1_xt;
366 for (int row : sellist)
368 // unique id - could be a horrible hash
370 String pdbIdStr = restable.getValueAt(row, idColumnIndex).toString();
371 String urlStr = restable.getValueAt(row, urlColumnIndex).toString();
372 String typeColumn = restable.getValueAt(row, typeColumnIndex)
374 SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
376 selectedSeqsToView.add(selectedSeq);
377 PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
378 if (pdbEntry == null)
380 pdbEntry = getFindEntry(pdbIdStr, selectedSeq.getAllPDBEntries());
383 if (pdbEntry == null)
385 pdbEntry = new PDBEntry();
386 pdbEntry.setId(pdbIdStr);
387 pdbEntry.setType(PDBEntry.Type.MMCIF);
388 if (!"PDBe".equalsIgnoreCase(typeColumn))
390 pdbEntry.setRetrievalUrl(urlStr);
392 selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
394 pdbEntriesToView[count++] = pdbEntry;
396 return pdbEntriesToView;
400 protected FTSRestRequest getLastFTSRequest()
402 return lastTdbRequest;
406 * generate a query for PDBFTS to retrieve structure metadata
408 * @param ftsRestRequest
413 public String buildPDBFTSQueryFor(FTSRestResponse upResponse)
415 List<String> pdbIds = new ArrayList<String>();
416 int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
417 int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
418 for (FTSData row : upResponse.getSearchSummary())
420 String id = (String) row.getSummaryData()[idx_modelId];
421 String provider = (String) row.getSummaryData()[idx_provider];
422 if ("PDBe".equalsIgnoreCase(provider))
427 return String.join(" OR ", pdbIds).toString();
431 * query PDBe for structure metadata
435 * @return FTSRestResponse via PDBStructureChooserQuerySource
437 public FTSRestResponse fetchStructuresMetaDataFor(
438 PDBStructureChooserQuerySource pdbquery,
439 FTSRestResponse upResponse) throws Exception
442 String pdb_Query = buildPDBFTSQueryFor(upResponse);
444 FTSRestResponse resultList;
445 FTSRestRequest pdbRequest = new FTSRestRequest();
446 pdbRequest.setAllowEmptySeq(false);
447 pdbRequest.setResponseSize(500);
448 pdbRequest.setFieldToSearchBy("(");
449 // pdbRequest.setFieldToSortBy("pdb_id");
450 pdbRequest.setWantedFields(
451 pdbquery.getDocFieldPrefs().getStructureSummaryFields());
452 pdbRequest.setSearchTerm(pdb_Query + ")");
453 resultList = pdbquery.executePDBFTSRestRequest(pdbRequest);
455 lastPdbRequest = pdbRequest;
459 public FTSRestResponse joinResponses(FTSRestResponse upResponse,
460 FTSRestResponse pdbResponse)
462 int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
464 int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
465 int pdbIdx = lastPdbRequest.getFieldIndex("PDB Id");
466 int pdbTitle_idx = lastPdbRequest.getFieldIndex("Title");
467 int tdbTitle_idx = getLastFTSRequest().getFieldIndex("Title");
469 List<FTSData> joinedRows = new ArrayList<FTSData>();
470 for (final FTSData row : upResponse.getSearchSummary())
472 String id = (String) row.getSummaryData()[idx_modelId];
473 String provider = (String) row.getSummaryData()[idx_provider];
474 if ("PDBe".equalsIgnoreCase(provider))
476 for (final FTSData pdbrow : pdbResponse.getSearchSummary())
478 String pdbid = (String) pdbrow.getSummaryData()[pdbIdx];
479 if (id.equalsIgnoreCase(pdbid))
481 row.getSummaryData()[tdbTitle_idx] = pdbrow
482 .getSummaryData()[pdbTitle_idx];
488 row.getSummaryData()[tdbTitle_idx] = "Model from TDB";