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