c127a78b25747d8b84319d494e936f12fe65fbd7
[jalview.git] / src / jalview / gui / StructureChooserQuerySource.java
1 package jalview.gui;
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.table.TableModel;
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.FTSData;
17 import jalview.fts.api.FTSDataColumnI;
18 import jalview.fts.api.FTSRestClientI;
19 import jalview.fts.core.FTSRestRequest;
20 import jalview.fts.core.FTSRestResponse;
21 import jalview.fts.service.pdb.PDBFTSRestClient;
22 import jalview.jbgui.GStructureChooser.FilterOption;
23
24 /**
25  * logic for querying sources of structural data for structures of sequences
26  * 
27  * @author jprocter
28  *
29  * @param <T>
30  */
31 public class StructureChooserQuerySource
32 {
33   private FTSRestRequest lastPdbRequest;
34
35   private FTSRestClientI pdbRestClient;
36
37   private static int MAX_QLENGTH = 7820;
38
39   public StructureChooserQuerySource()
40   {
41   }
42
43   public static StructureChooserQuerySource getPDBfts()
44   {
45     StructureChooserQuerySource pdbfts = new StructureChooserQuerySource();
46     pdbfts.pdbRestClient = PDBFTSRestClient.getInstance();
47     return pdbfts;
48   }
49
50   /**
51    * Builds a query string for a given sequences using its DBRef entries
52    * 
53    * @param seq
54    *          the sequences to build a query for
55    * @return the built query string
56    */
57
58   String buildQuery(SequenceI seq)
59   {
60     boolean isPDBRefsFound = false;
61     boolean isUniProtRefsFound = false;
62     StringBuilder queryBuilder = new StringBuilder();
63     Set<String> seqRefs = new LinkedHashSet<>();
64
65     /*
66      * note PDBs as DBRefEntry so they are not duplicated in query
67      */
68     Set<String> pdbids = new HashSet<>();
69
70     if (seq.getAllPDBEntries() != null
71             && queryBuilder.length() < MAX_QLENGTH)
72     {
73       for (PDBEntry entry : seq.getAllPDBEntries())
74       {
75         if (isValidSeqName(entry.getId()))
76         {
77           String id = entry.getId().toLowerCase();
78           queryBuilder.append("pdb_id:").append(id).append(" OR ");
79           isPDBRefsFound = true;
80           pdbids.add(id);
81         }
82       }
83     }
84
85     List<DBRefEntry> refs = seq.getDBRefs();
86     if (refs != null && refs.size() != 0)
87     {
88       for (int ib = 0, nb = refs.size(); ib < nb; ib++)
89       {
90         DBRefEntry dbRef = refs.get(ib);
91         if (isValidSeqName(getDBRefId(dbRef))
92                 && queryBuilder.length() < MAX_QLENGTH)
93         {
94           if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
95           {
96             queryBuilder.append("uniprot_accession:")
97                     .append(getDBRefId(dbRef)).append(" OR ");
98             queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
99                     .append(" OR ");
100             isUniProtRefsFound = true;
101           }
102           else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
103           {
104
105             String id = getDBRefId(dbRef).toLowerCase();
106             if (!pdbids.contains(id))
107             {
108               queryBuilder.append("pdb_id:").append(id).append(" OR ");
109               isPDBRefsFound = true;
110               pdbids.add(id);
111             }
112           }
113           else
114           {
115             seqRefs.add(getDBRefId(dbRef));
116           }
117         }
118       }
119     }
120
121     if (!isPDBRefsFound && !isUniProtRefsFound)
122     {
123       String seqName = seq.getName();
124       seqName = sanitizeSeqName(seqName);
125       String[] names = seqName.toLowerCase().split("\\|");
126       for (String name : names)
127       {
128         // System.out.println("Found name : " + name);
129         name.trim();
130         if (isValidSeqName(name))
131         {
132           seqRefs.add(name);
133         }
134       }
135
136       for (String seqRef : seqRefs)
137       {
138         queryBuilder.append("text:").append(seqRef).append(" OR ");
139       }
140     }
141
142     int endIndex = queryBuilder.lastIndexOf(" OR ");
143     if (queryBuilder.toString().length() < 6)
144     {
145       return null;
146     }
147     String query = queryBuilder.toString().substring(0, endIndex);
148     return query;
149   }
150
151   /**
152    * Remove the following special characters from input string +, -, &, !, (, ),
153    * {, }, [, ], ^, ", ~, *, ?, :, \
154    * 
155    * @param seqName
156    * @return
157    */
158   static String sanitizeSeqName(String seqName)
159   {
160     Objects.requireNonNull(seqName);
161     return seqName.replaceAll("\\[\\d*\\]", "")
162             .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
163   }
164
165   /**
166    * Ensures sequence ref names are not less than 3 characters and does not
167    * contain a database name
168    * 
169    * @param seqName
170    * @return
171    */
172   static boolean isValidSeqName(String seqName)
173   {
174     // System.out.println("seqName : " + seqName);
175     String ignoreList = "pdb,uniprot,swiss-prot";
176     if (seqName.length() < 3)
177     {
178       return false;
179     }
180     if (seqName.contains(":"))
181     {
182       return false;
183     }
184     seqName = seqName.toLowerCase();
185     for (String ignoredEntry : ignoreList.split(","))
186     {
187       if (seqName.contains(ignoredEntry))
188       {
189         return false;
190       }
191     }
192     return true;
193   }
194
195   static String getDBRefId(DBRefEntry dbRef)
196   {
197     String ref = dbRef.getAccessionId().replaceAll("GO:", "");
198     return ref;
199   }
200
201   /**
202    * FTSRestClient specific query builder to recover associated structure data
203    * records for a sequence
204    * 
205    * @param seq
206    *          - seq to generate a query for
207    * @param wantedFields
208    *          - fields to retrieve
209    * @param selectedFilterOpt
210    *          - criterion for ranking results (e.g. resolution)
211    * @param b
212    *          - sort ascending or descending
213    * @return
214    * @throws Exception
215    */
216   public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
217           Collection<FTSDataColumnI> wantedFields,
218           FilterOption selectedFilterOpt, boolean b) throws Exception
219   {
220     FTSRestResponse resultList;
221     FTSRestRequest pdbRequest = new FTSRestRequest();
222     pdbRequest.setAllowEmptySeq(false);
223     pdbRequest.setResponseSize(500);
224     pdbRequest.setFieldToSearchBy("(");
225     pdbRequest.setFieldToSortBy(selectedFilterOpt.getValue(), b);
226     pdbRequest.setWantedFields(wantedFields);
227     pdbRequest.setSearchTerm(buildQuery(seq) + ")");
228     pdbRequest.setAssociatedSequence(seq);
229     resultList = pdbRestClient.executeRequest(pdbRequest);
230
231     lastPdbRequest = pdbRequest;
232     return resultList;
233   }
234
235   /**
236    * FTSRestClient specific query builder to pick top ranked entry from a
237    * fetchStructuresMetaData query
238    * 
239    * @param seq
240    *          - seq to generate a query for
241    * @param wantedFields
242    *          - fields to retrieve
243    * @param selectedFilterOpt
244    *          - criterion for ranking results (e.g. resolution)
245    * @param b
246    *          - sort ascending or descending
247    * @return
248    * @throws Exception
249    */
250   public FTSRestResponse selectFirstRankedQuery(SequenceI seq,
251           Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
252           boolean b) throws Exception
253   {
254
255     FTSRestResponse resultList;
256     FTSRestRequest pdbRequest = new FTSRestRequest();
257     if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
258     {
259       pdbRequest.setAllowEmptySeq(false);
260       pdbRequest.setResponseSize(1);
261       pdbRequest.setFieldToSearchBy("(");
262       pdbRequest.setSearchTerm(buildQuery(seq) + ")");
263       pdbRequest.setWantedFields(wantedFields);
264       pdbRequest.setAssociatedSequence(seq);
265       pdbRequest.setFacet(true);
266       pdbRequest.setFacetPivot(fieldToFilterBy + ",entry_entity");
267       pdbRequest.setFacetPivotMinCount(1);
268     }
269     else
270     {
271       pdbRequest.setAllowEmptySeq(false);
272       pdbRequest.setResponseSize(1);
273       pdbRequest.setFieldToSearchBy("(");
274       pdbRequest.setFieldToSortBy(fieldToFilterBy, b);
275       pdbRequest.setSearchTerm(buildQuery(seq) + ")");
276       pdbRequest.setWantedFields(wantedFields);
277       pdbRequest.setAssociatedSequence(seq);
278     }
279     resultList = pdbRestClient.executeRequest(pdbRequest);
280
281     lastPdbRequest = pdbRequest;
282     return resultList;
283   }
284
285   public TableModel getTableModel(
286           Collection<FTSData> discoveredStructuresSet)
287   {
288     return FTSRestResponse.getTableModel(lastPdbRequest,
289             discoveredStructuresSet);
290   }
291
292 }