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 static final String FILTER_TDBEACONS_COVERAGE = "3d_beacons_coverage";
41 private static int MAX_QLENGTH = 7820;
43 protected FTSRestRequest lastTdbRequest;
45 protected FTSRestClientI tdbRestClient;
47 private FTSRestRequest lastPdbRequest;
49 public ThreeDBStructureChooserQuerySource()
51 tdbRestClient = TDBeaconsFTSRestClient.getInstance();
52 docFieldPrefs = new FTSDataColumnPreferences(
53 PreferenceSource.STRUCTURE_CHOOSER,
54 TDBeaconsFTSRestClient.getInstance());
59 * Builds a query string for a given sequences using its DBRef entries 3d
60 * Beacons is only useful for uniprot IDs
63 * the sequences to build a query for
64 * @return the built query string
67 public String buildQuery(SequenceI seq)
69 boolean isPDBRefsFound = false;
70 boolean isUniProtRefsFound = false;
71 StringBuilder queryBuilder = new StringBuilder();
72 Set<String> seqRefs = new LinkedHashSet<>();
75 * note PDBs as DBRefEntry so they are not duplicated in query
77 Set<String> pdbids = new HashSet<>();
79 List<DBRefEntry> refs = seq.getDBRefs();
80 if (refs != null && refs.size() != 0)
82 for (int ib = 0, nb = refs.size(); ib < nb; ib++)
84 DBRefEntry dbRef = refs.get(ib);
85 if (isValidSeqName(getDBRefId(dbRef))
86 && queryBuilder.length() < MAX_QLENGTH)
88 if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT)
89 && dbRef.isCanonical())
91 // TODO: pick best Uniprot accession
92 isUniProtRefsFound = true;
93 return getDBRefId(dbRef);
103 * Ensures sequence ref names are not less than 3 characters and does not
104 * contain a database name
109 static boolean isValidSeqName(String seqName)
111 // System.out.println("seqName : " + seqName);
112 String ignoreList = "pdb,uniprot,swiss-prot";
113 if (seqName.length() < 3)
117 if (seqName.contains(":"))
121 seqName = seqName.toLowerCase();
122 for (String ignoredEntry : ignoreList.split(","))
124 if (seqName.contains(ignoredEntry))
132 static String getDBRefId(DBRefEntry dbRef)
134 String ref = dbRef.getAccessionId().replaceAll("GO:", "");
139 * FTSRestClient specific query builder to recover associated structure data
140 * records for a sequence
143 * - seq to generate a query for
144 * @param wantedFields
145 * - fields to retrieve
146 * @param selectedFilterOpt
147 * - criterion for ranking results (e.g. resolution)
149 * - sort ascending or descending
153 public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
154 Collection<FTSDataColumnI> wantedFields,
155 FilterOption selectedFilterOpt, boolean b) throws Exception
157 FTSRestResponse resultList;
158 if (tdBeaconsFilter(selectedFilterOpt.getValue())) {
159 FTSRestRequest tdbRequest = getTDBeaconsRequest(seq, wantedFields);
160 resultList = tdbRestClient.executeRequest(tdbRequest);
162 lastTdbRequest = tdbRequest;
164 // Query the PDB and add additional metadata
165 FTSRestResponse pdbResponse = fetchStructuresMetaDataFor(getPDBQuerySource(), resultList);
166 FTSRestResponse joinedResp = joinResponses(resultList,
170 // use the PDBFTS directly
171 resultList = getPDBQuerySource().fetchStructuresMetaData(seq, wantedFields, selectedFilterOpt, b);
172 lastTdbRequest = getPDBQuerySource().lastPdbRequest;
173 lastPdbRequest = lastTdbRequest; // both queries the same - indicates we rank using PDBe
178 PDBStructureChooserQuerySource pdbQuerySource=null;
179 private PDBStructureChooserQuerySource getPDBQuerySource()
181 if (pdbQuerySource==null)
183 pdbQuerySource = new PDBStructureChooserQuerySource();
185 return pdbQuerySource;
188 private FTSRestRequest getTDBeaconsRequest(SequenceI seq,
189 Collection<FTSDataColumnI> wantedFields)
191 FTSRestRequest pdbRequest = new FTSRestRequest();
192 pdbRequest.setAllowEmptySeq(false);
193 pdbRequest.setResponseSize(500);
194 pdbRequest.setWantedFields(wantedFields);
195 String query = buildQuery(seq);
200 pdbRequest.setSearchTerm(query + ".json");
201 pdbRequest.setAssociatedSequence(seq);
206 public List<FilterOption> getAvailableFilterOptions(String VIEWS_FILTER)
208 List<FilterOption> filters = getPDBQuerySource().getAvailableFilterOptions(VIEWS_FILTER);
211 new FilterOption("3D-Beacons Coverage",
212 FILTER_TDBEACONS_COVERAGE, VIEWS_FILTER, true, this));
215 private boolean tdBeaconsFilter(String fieldToFilterBy)
217 return FILTER_TDBEACONS_COVERAGE.equals(fieldToFilterBy);
221 public boolean needsRefetch(FilterOption selectedFilterOpt)
223 return tdBeaconsFilter(selectedFilterOpt.getValue()) && lastPdbRequest!=lastTdbRequest;
226 * FTSRestClient specific query builder to pick top ranked entry from a
227 * fetchStructuresMetaData query
230 * - seq to generate a query for
231 * @param wantedFields
232 * - fields to retrieve
233 * @param selectedFilterOpt
234 * - criterion for ranking results (e.g. resolution)
236 * - sort ascending or descending
240 public FTSRestResponse selectFirstRankedQuery(SequenceI seq,
241 Collection<FTSData> collectedResults,
242 Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
243 boolean b) throws Exception
245 if (tdBeaconsFilter(fieldToFilterBy))
247 TDBResultAnalyser analyser = new TDBResultAnalyser(seq,
248 collectedResults, lastTdbRequest);
250 FTSRestResponse resultList = new FTSRestResponse();
252 List<FTSData> filteredResponse = analyser.getFilteredResponse();
254 List<FTSData> selectedStructures = analyser
255 .selectStructures(filteredResponse);
256 resultList.setNumberOfItemsFound(selectedStructures.size());
257 resultList.setSearchSummary(selectedStructures);
260 // Fall back to PDBe rankings
261 return getPDBQuerySource().selectFirstRankedQuery(seq, collectedResults, wantedFields, fieldToFilterBy, b);
266 public PDBEntry[] collectSelectedRows(JTable restable, int[] selectedRows,
267 List<SequenceI> selectedSeqsToView)
269 int refSeqColIndex = restable.getColumn("Ref Sequence").getModelIndex();
271 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
273 int idColumnIndex = restable.getColumn("Model id").getModelIndex();
274 int urlColumnIndex = restable.getColumn("Url").getModelIndex();
275 int typeColumnIndex = restable.getColumn("Provider").getModelIndex();
276 int categoryColumnIndex = restable.getColumn("Model Category")
278 final int up_start_idx = restable.getColumn("Uniprot Start").getModelIndex();
279 final int up_end_idx = restable.getColumn("Uniprot End").getModelIndex();
283 Integer[] sellist = new Integer[selectedRows.length];
284 for (Integer row: selectedRows)
288 // Sort rows by coverage
289 Arrays.sort(sellist,new Comparator<Integer>()
292 public int compare(Integer o1, Integer o2)
294 int o1_xt = ((Integer)restable.getValueAt(o1, up_end_idx)) - (Integer)restable.getValueAt(o1, up_start_idx);
295 int o2_xt = ((Integer)restable.getValueAt(o2, up_end_idx)) - (Integer)restable.getValueAt(o2, up_start_idx);
301 for (int row : sellist)
303 // unique id - could be a horrible hash
305 String pdbIdStr = restable.getValueAt(row, idColumnIndex).toString();
306 String urlStr = restable.getValueAt(row, urlColumnIndex).toString();
307 String typeColumn = restable.getValueAt(row, typeColumnIndex)
309 SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
311 selectedSeqsToView.add(selectedSeq);
312 PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
313 if (pdbEntry == null)
315 pdbEntry = getFindEntry(pdbIdStr, selectedSeq.getAllPDBEntries());
318 if (pdbEntry == null)
320 pdbEntry = new PDBEntry();
321 pdbEntry.setId(pdbIdStr);
322 pdbEntry.setType(PDBEntry.Type.MMCIF);
323 if (!"PDBe".equalsIgnoreCase(typeColumn))
325 pdbEntry.setRetrievalUrl(urlStr);
327 selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
329 pdbEntriesToView[count++] = pdbEntry;
331 return pdbEntriesToView;
335 protected FTSRestRequest getLastFTSRequest()
337 return lastTdbRequest;
341 * generate a query for PDBFTS to retrieve structure metadata
343 * @param ftsRestRequest
348 public String buildPDBFTSQueryFor(FTSRestResponse upResponse)
350 List<String> pdbIds = new ArrayList<String>();
351 int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
352 int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
353 for (FTSData row : upResponse.getSearchSummary())
355 String id = (String) row.getSummaryData()[idx_modelId];
356 String provider = (String) row.getSummaryData()[idx_provider];
357 if ("PDBe".equalsIgnoreCase(provider))
362 return String.join(" OR ", pdbIds).toString();
366 * query PDBe for structure metadata
370 * @return FTSRestResponse via PDBStructureChooserQuerySource
372 public FTSRestResponse fetchStructuresMetaDataFor(
373 PDBStructureChooserQuerySource pdbquery,
374 FTSRestResponse upResponse) throws Exception
377 String pdb_Query = buildPDBFTSQueryFor(upResponse);
379 FTSRestResponse resultList;
380 FTSRestRequest pdbRequest = new FTSRestRequest();
381 pdbRequest.setAllowEmptySeq(false);
382 pdbRequest.setResponseSize(500);
383 pdbRequest.setFieldToSearchBy("(");
384 // pdbRequest.setFieldToSortBy("pdb_id");
385 pdbRequest.setWantedFields(
386 pdbquery.getDocFieldPrefs().getStructureSummaryFields());
387 pdbRequest.setSearchTerm(pdb_Query + ")");
388 resultList = pdbquery.executePDBFTSRestRequest(pdbRequest);
390 lastPdbRequest = pdbRequest;
394 public FTSRestResponse joinResponses(FTSRestResponse upResponse,
395 FTSRestResponse pdbResponse)
397 int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
399 int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
400 int pdbIdx = lastPdbRequest.getFieldIndex("PDB Id");
401 int pdbTitle_idx = lastPdbRequest.getFieldIndex("Title");
402 int tdbTitle_idx = getLastFTSRequest().getFieldIndex("Title");
404 List<FTSData> joinedRows = new ArrayList<FTSData>();
405 for (final FTSData row : upResponse.getSearchSummary())
407 String id = (String) row.getSummaryData()[idx_modelId];
408 String provider = (String) row.getSummaryData()[idx_provider];
409 if ("PDBe".equalsIgnoreCase(provider))
411 for (final FTSData pdbrow : pdbResponse.getSearchSummary())
413 String pdbid = (String) pdbrow.getSummaryData()[pdbIdx];
414 if (id.equalsIgnoreCase(pdbid))
416 row.getSummaryData()[tdbTitle_idx] = pdbrow
417 .getSummaryData()[pdbTitle_idx];
421 row.getSummaryData()[tdbTitle_idx] = "Model from TDB";