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