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