JAL-3746 release notes and what’s new for 2.11.2 - in progress
[jalview.git] / src / jalview / gui / structurechooser / StructureChooserQuerySource.java
1 package jalview.gui.structurechooser;
2
3 import java.util.Collection;
4 import java.util.List;
5 import java.util.Objects;
6 import java.util.Vector;
7
8 import javax.swing.JTable;
9 import javax.swing.table.TableModel;
10
11 import jalview.datamodel.DBRefEntry;
12 import jalview.datamodel.PDBEntry;
13 import jalview.datamodel.SequenceI;
14 import jalview.fts.api.FTSData;
15 import jalview.fts.api.FTSDataColumnI;
16 import jalview.fts.api.FTSRestClientI;
17 import jalview.fts.core.FTSDataColumnPreferences;
18 import jalview.fts.core.FTSRestRequest;
19 import jalview.fts.core.FTSRestResponse;
20 import jalview.jbgui.FilterOption;
21
22 /**
23  * logic for querying sources of structural data for structures of sequences
24  * 
25  * @author jprocter
26  *
27  * @param <T>
28  */
29 public abstract class StructureChooserQuerySource
30 {
31
32   protected FTSDataColumnPreferences docFieldPrefs;
33
34   /**
35    * max length of a GET URL (probably :( )
36    */
37   protected static int MAX_QLENGTH = 7820;
38
39   public StructureChooserQuerySource()
40   {
41   }
42
43   public static StructureChooserQuerySource getPDBfts()
44   {
45     return new PDBStructureChooserQuerySource();
46   }
47
48   public static StructureChooserQuerySource getTDBfts()
49   {
50     return new ThreeDBStructureChooserQuerySource();
51   }
52
53   public FTSDataColumnPreferences getDocFieldPrefs()
54   {
55     return docFieldPrefs;
56   }
57
58   public void setDocFieldPrefs(FTSDataColumnPreferences docFieldPrefs)
59   {
60     this.docFieldPrefs = docFieldPrefs;
61   }
62
63   public FTSDataColumnPreferences getInitialFieldPreferences()
64   {
65     return docFieldPrefs;
66   }
67
68   /**
69    * Builds a query string for a given sequences using its DBRef entries
70    * 
71    * @param seq
72    *          the sequences to build a query for
73    * @return the built query string
74    */
75
76   public abstract String buildQuery(SequenceI seq);
77
78   /**
79    * Remove the following special characters from input string +, -, &, !, (, ),
80    * {, }, [, ], ^, ", ~, *, ?, :, \
81    * 
82    * @param seqName
83    * @return
84    */
85   public static String sanitizeSeqName(String seqName)
86   {
87     Objects.requireNonNull(seqName);
88     return seqName.replaceAll("\\[\\d*\\]", "")
89             .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
90   }
91
92   /**
93    * Ensures sequence ref names are not less than 3 characters and does not
94    * contain a database name
95    * 
96    * @param seqName
97    * @return
98    */
99   static boolean isValidSeqName(String seqName)
100   {
101     // System.out.println("seqName : " + seqName);
102     String ignoreList = "pdb,uniprot,swiss-prot";
103     if (seqName.length() < 3)
104     {
105       return false;
106     }
107     if (seqName.contains(":"))
108     {
109       return false;
110     }
111     seqName = seqName.toLowerCase();
112     for (String ignoredEntry : ignoreList.split(","))
113     {
114       if (seqName.contains(ignoredEntry))
115       {
116         return false;
117       }
118     }
119     return true;
120   }
121
122   static String getDBRefId(DBRefEntry dbRef)
123   {
124     String ref = dbRef.getAccessionId().replaceAll("GO:", "");
125     return ref;
126   }
127
128   static PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
129   {
130     Objects.requireNonNull(id);
131     Objects.requireNonNull(pdbEntries);
132     PDBEntry foundEntry = null;
133     for (PDBEntry entry : pdbEntries)
134     {
135       if (entry.getId().equalsIgnoreCase(id))
136       {
137         return entry;
138       }
139     }
140     return foundEntry;
141   }
142
143   /**
144    * FTSRestClient specific query builder to recover associated structure data
145    * records for a sequence
146    * 
147    * @param seq
148    *          - seq to generate a query for
149    * @param wantedFields
150    *          - fields to retrieve
151    * @param selectedFilterOpt
152    *          - criterion for ranking results (e.g. resolution)
153    * @param b
154    *          - sort ascending or descending
155    * @return
156    * @throws Exception
157    */
158   public abstract FTSRestResponse fetchStructuresMetaData(SequenceI seq,
159           Collection<FTSDataColumnI> wantedFields,
160           FilterOption selectedFilterOpt, boolean b) throws Exception;
161
162   /**
163    * FTSRestClient specific query builder to pick top ranked entry from a
164    * fetchStructuresMetaData query
165    * 
166    * @param seq
167    *          - seq to generate a query for
168    * @param discoveredStructuresSet
169    *          - existing set of entries - allows client side selection
170    * @param wantedFields
171    *          - fields to retrieve
172    * @param selectedFilterOpt
173    *          - criterion for ranking results (e.g. resolution)
174    * @param b
175    *          - sort ascending or descending
176    * @return
177    * @throws Exception
178    */
179   public abstract FTSRestResponse selectFirstRankedQuery(SequenceI seq,
180           Collection<FTSData> discoveredStructuresSet,
181           Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
182           boolean b) throws Exception;
183
184   /**
185    * 
186    * @param discoveredStructuresSet
187    * @return the table model for the given result set for this engine
188    */
189   public TableModel getTableModel(
190           Collection<FTSData> discoveredStructuresSet)
191   {
192     return FTSRestResponse.getTableModel(getLastFTSRequest(),
193             discoveredStructuresSet);
194   }
195
196   protected abstract FTSRestRequest getLastFTSRequest();
197
198   public abstract PDBEntry[] collectSelectedRows(JTable restable,
199           int[] selectedRows, List<SequenceI> selectedSeqsToView);
200
201   /**
202    * @param VIEWS_FILTER
203    *          - a String key that can be used by the caller to tag the returned
204    *          filter options to distinguish them in a collection
205    * @return list of FilterOption - convention is that the last one in the list
206    *         will be constructed with 'addSeparator==true'
207    */
208   public abstract List<FilterOption> getAvailableFilterOptions(
209           String VIEWS_FILTER);
210
211   /**
212    * construct a structure chooser query source for the given set of sequences
213    * 
214    * @param selectedSeqs
215    * @return PDBe or 3DB query source
216    */
217   public static StructureChooserQuerySource getQuerySourceFor(
218           SequenceI[] selectedSeqs)
219   {
220     ThreeDBStructureChooserQuerySource tdbSource = new ThreeDBStructureChooserQuerySource();
221     boolean hasUniprot = false, hasCanonical = false;
222     boolean hasNA = false, hasProtein = false;
223     int protWithoutUni = 0;
224     int protWithoutCanon = 0;
225     for (SequenceI seq : selectedSeqs)
226     {
227       hasNA |= !seq.isProtein();
228       hasProtein |= seq.isProtein();
229       if (seq.isProtein())
230       {
231         int refsAvailable = ThreeDBStructureChooserQuerySource
232                 .checkUniprotRefs(seq.getDBRefs());
233         if (refsAvailable > -2)
234         {
235           if (refsAvailable > -1)
236           {
237             hasCanonical = true;
238           } else {
239             protWithoutCanon++;
240           }
241           hasUniprot = true;
242         } else {
243           protWithoutUni++;
244           
245         }
246       }
247     }
248     //
249     // logic: all canonicals - no fetchdb
250     // some uniprot no canonicals: defer to PDB, user can optionally fetch
251     //
252     if (hasProtein && hasCanonical && !hasNA && protWithoutCanon == 0 && protWithoutUni == 0)
253
254     {
255       return tdbSource;
256     }
257     return new PDBStructureChooserQuerySource();
258   }
259
260   /**
261    * some filter options may mean the original query needs to be executed again.
262    * 
263    * @param selectedFilterOpt
264    * @return true if the fetchStructuresMetadata method needs to be called again
265    */
266   public abstract boolean needsRefetch(FilterOption selectedFilterOpt);
267
268   public void updateAvailableFilterOptions(String VIEWS_FILTER,
269           List<FilterOption> xtantOptions, Collection<FTSData> lastFTSData)
270   {
271     // TODO Auto-generated method stub
272
273   }
274 }