727d8e08437a2a3a9250723b65511e69b2ab9b8a
[jalview.git] / src / jalview / gui / structurechooser / PDBStructureChooserQuerySource.java
1 package jalview.gui.structurechooser;
2
3 import java.util.Locale;
4
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.HashSet;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Objects;
11 import java.util.Set;
12
13 import javax.swing.JTable;
14 import javax.swing.table.TableModel;
15
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.pdb.PDBFTSRestClient;
28 import jalview.jbgui.FilterOption;
29 import jalview.util.MessageManager;
30
31 /**
32  * logic for querying the PDBe API for structures of sequences
33  * 
34  * @author jprocter
35  */
36 public class PDBStructureChooserQuerySource
37         extends StructureChooserQuerySource
38 {
39
40   private static int MAX_QLENGTH = 7820;
41
42   protected FTSRestRequest lastPdbRequest;
43
44   protected FTSRestClientI pdbRestClient;
45
46   public PDBStructureChooserQuerySource()
47   {
48     pdbRestClient = PDBFTSRestClient.getInstance();
49     docFieldPrefs = new FTSDataColumnPreferences(
50             PreferenceSource.STRUCTURE_CHOOSER,
51             PDBFTSRestClient.getInstance());
52
53   }
54
55
56   /**
57    * Builds a query string for a given sequences using its DBRef entries
58    * 
59    * @param seq
60    *          the sequences to build a query for
61    * @return the built query string
62    */
63
64   public String buildQuery(SequenceI seq)
65   {
66     boolean isPDBRefsFound = false;
67     boolean isUniProtRefsFound = false;
68     StringBuilder queryBuilder = new StringBuilder();
69     Set<String> seqRefs = new LinkedHashSet<>();
70
71     /*
72      * note PDBs as DBRefEntry so they are not duplicated in query
73      */
74     Set<String> pdbids = new HashSet<>();
75
76     if (seq.getAllPDBEntries() != null
77             && queryBuilder.length() < MAX_QLENGTH)
78     {
79       for (PDBEntry entry : seq.getAllPDBEntries())
80       {
81         if (isValidSeqName(entry.getId()))
82         {
83           String id = entry.getId().toLowerCase(Locale.ROOT);
84           queryBuilder.append("pdb_id:").append(id).append(" OR ");
85           isPDBRefsFound = true;
86           pdbids.add(id);
87         }
88       }
89     }
90
91     List<DBRefEntry> refs = seq.getDBRefs();
92     if (refs != null && refs.size() != 0)
93     {
94       for (int ib = 0, nb = refs.size(); ib < nb; ib++)
95       {
96         DBRefEntry dbRef = refs.get(ib);
97         if (isValidSeqName(getDBRefId(dbRef))
98                 && queryBuilder.length() < MAX_QLENGTH)
99         {
100           if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
101           {
102             queryBuilder.append("uniprot_accession:")
103                     .append(getDBRefId(dbRef)).append(" OR ");
104             queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
105                     .append(" OR ");
106             isUniProtRefsFound = true;
107           }
108           else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
109           {
110
111             String id = getDBRefId(dbRef).toLowerCase(Locale.ROOT);
112             if (!pdbids.contains(id))
113             {
114               queryBuilder.append("pdb_id:").append(id).append(" OR ");
115               isPDBRefsFound = true;
116               pdbids.add(id);
117             }
118           }
119           else
120           {
121             seqRefs.add(getDBRefId(dbRef));
122           }
123         }
124       }
125     }
126
127     if (!isPDBRefsFound && !isUniProtRefsFound)
128     {
129       String seqName = seq.getName();
130       seqName = sanitizeSeqName(seqName);
131       String[] names = seqName.toLowerCase(Locale.ROOT).split("\\|");
132       for (String name : names)
133       {
134         // System.out.println("Found name : " + name);
135         name.trim();
136         if (isValidSeqName(name))
137         {
138           seqRefs.add(name);
139         }
140       }
141
142       for (String seqRef : seqRefs)
143       {
144         queryBuilder.append("text:").append(seqRef).append(" OR ");
145       }
146     }
147
148     int endIndex = queryBuilder.lastIndexOf(" OR ");
149     if (queryBuilder.toString().length() < 6)
150     {
151       return null;
152     }
153     String query = queryBuilder.toString().substring(0, endIndex);
154     return query;
155   }
156
157   /**
158    * Remove the following special characters from input string +, -, &, !, (, ),
159    * {, }, [, ], ^, ", ~, *, ?, :, \
160    * 
161    * @param seqName
162    * @return
163    */
164   public static String sanitizeSeqName(String seqName)
165   {
166     Objects.requireNonNull(seqName);
167     return seqName.replaceAll("\\[\\d*\\]", "")
168             .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
169   }
170
171   /**
172    * Ensures sequence ref names are not less than 3 characters and does not
173    * contain a database name
174    * 
175    * @param seqName
176    * @return
177    */
178   static boolean isValidSeqName(String seqName)
179   {
180     // System.out.println("seqName : " + seqName);
181     String ignoreList = "pdb,uniprot,swiss-prot";
182     if (seqName.length() < 3)
183     {
184       return false;
185     }
186     if (seqName.contains(":"))
187     {
188       return false;
189     }
190     seqName = seqName.toLowerCase(Locale.ROOT);
191     for (String ignoredEntry : ignoreList.split(","))
192     {
193       if (seqName.contains(ignoredEntry))
194       {
195         return false;
196       }
197     }
198     return true;
199   }
200
201   static String getDBRefId(DBRefEntry dbRef)
202   {
203     String ref = dbRef.getAccessionId().replaceAll("GO:", "");
204     return ref;
205   }
206
207   /**
208    * FTSRestClient specific query builder to recover associated structure data
209    * records for a sequence
210    * 
211    * @param seq
212    *          - seq to generate a query for
213    * @param wantedFields
214    *          - fields to retrieve
215    * @param selectedFilterOpt
216    *          - criterion for ranking results (e.g. resolution)
217    * @param b
218    *          - sort ascending or descending
219    * @return
220    * @throws Exception
221    */
222   public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
223           Collection<FTSDataColumnI> wantedFields,
224           FilterOption selectedFilterOpt, boolean b) throws Exception
225   {
226     FTSRestResponse resultList;
227     FTSRestRequest pdbRequest = new FTSRestRequest();
228     pdbRequest.setAllowEmptySeq(false);
229     pdbRequest.setResponseSize(500);
230     pdbRequest.setFieldToSearchBy("(");
231     pdbRequest.setFieldToSortBy(selectedFilterOpt.getValue(), b);
232     pdbRequest.setWantedFields(wantedFields);
233     pdbRequest.setSearchTerm(buildQuery(seq) + ")");
234     pdbRequest.setAssociatedSequence(seq);
235     resultList = pdbRestClient.executeRequest(pdbRequest);
236
237     lastPdbRequest = pdbRequest;
238     return resultList;
239   }
240   public List<FilterOption> getAvailableFilterOptions(String VIEWS_FILTER)
241   {
242     List<FilterOption> filters = new ArrayList<FilterOption>();
243     filters.add(new FilterOption("PDBe "+
244             MessageManager.getString("label.best_quality"),
245             "overall_quality", VIEWS_FILTER, false,this));
246     filters.add(new FilterOption("PDBe "+
247             MessageManager.getString("label.best_resolution"),
248             "resolution", VIEWS_FILTER, false,this));
249     filters.add(new FilterOption("PDBe "+
250             MessageManager.getString("label.most_protein_chain"),
251             "number_of_protein_chains", VIEWS_FILTER, false,this));
252     filters.add(new FilterOption("PDBe "+
253             MessageManager.getString("label.most_bound_molecules"),
254             "number_of_bound_molecules", VIEWS_FILTER, false,this));
255     filters.add(new FilterOption("PDBe "+
256             MessageManager.getString("label.most_polymer_residues"),
257             "number_of_polymer_residues", VIEWS_FILTER, true,this));
258   
259     return filters;
260   }
261
262   @Override
263   public boolean needsRefetch(FilterOption selectedFilterOpt)
264   {
265     // PDBe queries never need a refetch first
266     return false;
267   }
268
269   /**
270    * FTSRestClient specific query builder to pick top ranked entry from a
271    * fetchStructuresMetaData query
272    * 
273    * @param seq
274    *          - seq to generate a query for
275    * @param wantedFields
276    *          - fields to retrieve
277    * @param selectedFilterOpt
278    *          - criterion for ranking results (e.g. resolution)
279    * @param b
280    *          - sort ascending or descending
281    * @return
282    * @throws Exception
283    */
284   public FTSRestResponse selectFirstRankedQuery(SequenceI seq, Collection<FTSData> collectedResults,
285           Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
286           boolean b) throws Exception
287   {
288
289     FTSRestResponse resultList;
290     FTSRestRequest pdbRequest = new FTSRestRequest();
291     if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
292     {
293       pdbRequest.setAllowEmptySeq(false);
294       pdbRequest.setResponseSize(1);
295       pdbRequest.setFieldToSearchBy("(");
296       pdbRequest.setSearchTerm(buildQuery(seq) + ")");
297       pdbRequest.setWantedFields(wantedFields);
298       pdbRequest.setAssociatedSequence(seq);
299       pdbRequest.setFacet(true);
300       pdbRequest.setFacetPivot(fieldToFilterBy + ",entry_entity");
301       pdbRequest.setFacetPivotMinCount(1);
302     }
303     else
304     {
305       pdbRequest.setAllowEmptySeq(false);
306       pdbRequest.setResponseSize(1);
307       pdbRequest.setFieldToSearchBy("(");
308       pdbRequest.setFieldToSortBy(fieldToFilterBy, b);
309       pdbRequest.setSearchTerm(buildQuery(seq) + ")");
310       pdbRequest.setWantedFields(wantedFields);
311       pdbRequest.setAssociatedSequence(seq);
312     }
313     resultList = pdbRestClient.executeRequest(pdbRequest);
314
315     lastPdbRequest = pdbRequest;
316     return resultList;
317   }
318
319
320   @Override
321   public PDBEntry[] collectSelectedRows(JTable restable, int[] selectedRows,
322           List<SequenceI> selectedSeqsToView)
323   {
324     int refSeqColIndex = restable.getColumn("Ref Sequence")
325             .getModelIndex();
326
327     PDBEntry[] pdbEntriesToView=new PDBEntry[selectedRows.length];
328     int count = 0;
329     int idColumnIndex=-1;
330     boolean fromTDB=true;
331     idColumnIndex = restable.getColumn("PDB Id").getModelIndex();
332     
333     for (int row : selectedRows)
334     {
335       
336       String pdbIdStr = restable.getValueAt(row,idColumnIndex)
337               .toString();
338       SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
339               refSeqColIndex);
340       selectedSeqsToView.add(selectedSeq);
341       PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
342       if (pdbEntry == null)
343       {
344         pdbEntry = getFindEntry(pdbIdStr,
345                 selectedSeq.getAllPDBEntries());
346       }
347
348       if (pdbEntry == null)
349       {
350         pdbEntry = new PDBEntry();
351         pdbEntry.setId(pdbIdStr);
352         pdbEntry.setType(PDBEntry.Type.MMCIF);
353         selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
354       }
355       pdbEntriesToView[count++] = pdbEntry;
356     }
357     return pdbEntriesToView;
358   }
359
360
361   @Override
362   protected FTSRestRequest getLastFTSRequest()
363   {
364     return lastPdbRequest;
365   }
366
367
368   public FTSRestResponse executePDBFTSRestRequest(FTSRestRequest pdbRequest) throws Exception
369   {
370     return pdbRestClient.executeRequest(pdbRequest);
371   }
372
373 }