JAL-3829 refactored FilterOption provider to the StructureChooserQuerySource implemen...
[jalview.git] / src / jalview / gui / structurechooser / ThreeDBStructureChooserQuerySource.java
1 package jalview.gui.structurechooser;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
6 import java.util.LinkedHashSet;
7 import java.util.List;
8 import java.util.Set;
9
10 import javax.swing.JTable;
11
12 import jalview.datamodel.DBRefEntry;
13 import jalview.datamodel.DBRefSource;
14 import jalview.datamodel.PDBEntry;
15 import jalview.datamodel.SequenceI;
16 import jalview.fts.api.FTSDataColumnI;
17 import jalview.fts.core.FTSDataColumnPreferences;
18 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
19 import jalview.fts.core.FTSRestRequest;
20 import jalview.fts.core.FTSRestResponse;
21 import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
22 import jalview.jbgui.FilterOption;
23 import jalview.util.MessageManager;
24
25 /**
26  * logic for querying the PDBe API for structures of sequences
27  * 
28  * @author jprocter
29  */
30 public class ThreeDBStructureChooserQuerySource
31         extends StructureChooserQuerySource
32 {
33
34   private static int MAX_QLENGTH = 7820;
35
36   public ThreeDBStructureChooserQuerySource()
37   {
38     pdbRestClient = TDBeaconsFTSRestClient.getInstance();
39     docFieldPrefs = new FTSDataColumnPreferences(
40             PreferenceSource.STRUCTURE_CHOOSER,
41             TDBeaconsFTSRestClient.getInstance());
42
43   }
44
45
46   /**
47    * Builds a query string for a given sequences using its DBRef entries
48    * 3d Beacons is only useful for uniprot IDs
49    * @param seq
50    *          the sequences to build a query for
51    * @return the built query string
52    */
53
54   public String buildQuery(SequenceI seq)
55   {
56     boolean isPDBRefsFound = false;
57     boolean isUniProtRefsFound = false;
58     StringBuilder queryBuilder = new StringBuilder();
59     Set<String> seqRefs = new LinkedHashSet<>();
60
61     /*
62      * note PDBs as DBRefEntry so they are not duplicated in query
63      */
64     Set<String> pdbids = new HashSet<>();
65
66     List<DBRefEntry> refs = seq.getDBRefs();
67     if (refs != null && refs.size() != 0)
68     {
69       for (int ib = 0, nb = refs.size(); ib < nb; ib++)
70       {
71         DBRefEntry dbRef = refs.get(ib);
72         if (isValidSeqName(getDBRefId(dbRef))
73                 && queryBuilder.length() < MAX_QLENGTH)
74         {
75           if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT) && dbRef.isCanonical())
76           {
77             // TODO: pick best Uniprot accession 
78             isUniProtRefsFound=true;
79             return getDBRefId(dbRef);
80             
81           }
82         }
83       }
84     }
85     return null;
86   }
87
88  
89
90   /**
91    * Ensures sequence ref names are not less than 3 characters and does not
92    * contain a database name
93    * 
94    * @param seqName
95    * @return
96    */
97   static boolean isValidSeqName(String seqName)
98   {
99     // System.out.println("seqName : " + seqName);
100     String ignoreList = "pdb,uniprot,swiss-prot";
101     if (seqName.length() < 3)
102     {
103       return false;
104     }
105     if (seqName.contains(":"))
106     {
107       return false;
108     }
109     seqName = seqName.toLowerCase();
110     for (String ignoredEntry : ignoreList.split(","))
111     {
112       if (seqName.contains(ignoredEntry))
113       {
114         return false;
115       }
116     }
117     return true;
118   }
119
120   static String getDBRefId(DBRefEntry dbRef)
121   {
122     String ref = dbRef.getAccessionId().replaceAll("GO:", "");
123     return ref;
124   }
125
126   /**
127    * FTSRestClient specific query builder to recover associated structure data
128    * records for a sequence
129    * 
130    * @param seq
131    *          - seq to generate a query for
132    * @param wantedFields
133    *          - fields to retrieve
134    * @param selectedFilterOpt
135    *          - criterion for ranking results (e.g. resolution)
136    * @param b
137    *          - sort ascending or descending
138    * @return
139    * @throws Exception
140    */
141   public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
142           Collection<FTSDataColumnI> wantedFields,
143           FilterOption selectedFilterOpt, boolean b) throws Exception
144   {
145     FTSRestResponse resultList;
146     FTSRestRequest pdbRequest = getTDBeaconsRequest(seq, wantedFields);
147     resultList = pdbRestClient.executeRequest(pdbRequest);
148
149     lastPdbRequest = pdbRequest;
150     return resultList;
151   }
152   
153
154   private FTSRestRequest getTDBeaconsRequest(SequenceI seq, Collection<FTSDataColumnI> wantedFields)
155   {
156     FTSRestRequest pdbRequest = new FTSRestRequest();
157     pdbRequest.setAllowEmptySeq(false);
158     pdbRequest.setResponseSize(500);
159     pdbRequest.setWantedFields(wantedFields);
160     String query = buildQuery(seq);
161     if (query==null)  {
162       return null;
163     }
164     pdbRequest.setSearchTerm(query + ".json");
165     pdbRequest.setAssociatedSequence(seq);
166     return pdbRequest;
167   }
168
169 @Override
170   public List<FilterOption> getAvailableFilterOptions(String VIEWS_FILTER)
171   {
172     List<FilterOption> filters = new ArrayList<FilterOption>();
173     filters.add(new FilterOption(
174             MessageManager.getString("label.best_quality"),
175             "overall_quality", VIEWS_FILTER, false));
176     filters.add(new FilterOption(
177             MessageManager.getString("label.best_resolution"),
178             "resolution", VIEWS_FILTER, false));
179     filters.add(new FilterOption(
180             MessageManager.getString("label.most_protein_chain"),
181             "number_of_protein_chains", VIEWS_FILTER, false));
182     filters.add(new FilterOption(
183             MessageManager.getString("label.most_bound_molecules"),
184             "number_of_bound_molecules", VIEWS_FILTER, false));
185     filters.add(new FilterOption(
186             MessageManager.getString("label.most_polymer_residues"),
187             "number_of_polymer_residues", VIEWS_FILTER, true));
188   
189     return filters;
190   }
191   /**
192    * FTSRestClient specific query builder to pick top ranked entry from a
193    * fetchStructuresMetaData query
194    * 
195    * @param seq
196    *          - seq to generate a query for
197    * @param wantedFields
198    *          - fields to retrieve
199    * @param selectedFilterOpt
200    *          - criterion for ranking results (e.g. resolution)
201    * @param b
202    *          - sort ascending or descending
203    * @return
204    * @throws Exception
205    */
206   public FTSRestResponse selectFirstRankedQuery(SequenceI seq,
207           Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
208           boolean b) throws Exception
209   {
210
211     FTSRestResponse resultList;
212     FTSRestRequest pdbRequest = getTDBeaconsRequest(seq, wantedFields);
213     if (pdbRequest == null) {
214       return null;
215     }
216     pdbRequest.setResponseSize(1);
217     resultList = pdbRestClient.executeRequest(pdbRequest);
218     
219     // TODO: client side filtering - sort results and pick top one (or N)
220
221     lastPdbRequest = pdbRequest;
222     return resultList;
223   }
224
225   @Override
226   public PDBEntry[] collectSelectedRows(JTable restable, int[] selectedRows,
227           List<SequenceI> selectedSeqsToView)
228   {
229     int refSeqColIndex = restable.getColumn("Ref Sequence")
230             .getModelIndex();
231
232     PDBEntry[] pdbEntriesToView=new PDBEntry[selectedRows.length];
233     int count = 0;
234     int idColumnIndex = restable.getColumn("Model id").getModelIndex();
235     int urlColumnIndex = restable.getColumn("Url").getModelIndex();
236     int typeColumnIndex = restable.getColumn("Provider").getModelIndex();
237     int categoryColumnIndex = restable.getColumn("Model Category").getModelIndex();
238     
239     for (int row : selectedRows)
240     {
241       // unique id - could be a horrible hash
242       
243       String pdbIdStr = restable.getValueAt(row,idColumnIndex)
244               .toString();
245       String urlStr = restable.getValueAt(row,urlColumnIndex)
246               .toString();
247       String typeColumn = restable.getValueAt(row,typeColumnIndex)
248               .toString();
249       SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
250               refSeqColIndex);
251       selectedSeqsToView.add(selectedSeq);
252       PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
253       if (pdbEntry == null)
254       {
255         pdbEntry = getFindEntry(pdbIdStr,
256                 selectedSeq.getAllPDBEntries());
257       }
258
259       if (pdbEntry == null)
260       {
261         pdbEntry = new PDBEntry();
262         pdbEntry.setId(pdbIdStr);
263         pdbEntry.setType(PDBEntry.Type.MMCIF);
264         if (!"PDBe".equalsIgnoreCase(typeColumn))
265         {
266           pdbEntry.setRetrievalUrl(urlStr);
267         }
268         selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
269       }
270       pdbEntriesToView[count++] = pdbEntry;
271     }
272     return pdbEntriesToView;
273   }
274 }