0bca0709c34b00663c302f8f74cad2dabcd7dc89
[jalview.git] / src / jalview / fts / core / FTSRestClient.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.fts.core;
22
23 import java.util.Locale;
24
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.Objects;
33
34 import jalview.fts.api.FTSDataColumnI;
35 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
36 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
37 import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
38 import jalview.fts.api.FTSRestClientI;
39
40 /**
41  * Base class providing implementation for common methods defined in
42  * FTSRestClientI
43  * 
44  * @author tcnofoegbu
45  * 
46  * @note implementations MUST be accessed as a singleton.
47  */
48 public abstract class FTSRestClient implements FTSRestClientI
49 {
50   protected Collection<FTSDataColumnI> dataColumns = new ArrayList<>();
51
52   protected Collection<FTSDataColumnGroupI> dataColumnGroups = new ArrayList<>();
53
54   protected Collection<FTSDataColumnI> searchableDataColumns = new ArrayList<>();
55
56   protected Collection<FTSDataColumnI> defaulDisplayedDataColumns = new ArrayList<>();
57
58   protected FTSDataColumnI primaryKeyColumn;
59
60   private String primaryKeyColumnCode = null;
61
62   private int defaultResponsePageSize = 100;
63
64   protected HashMap<String,String> mockQueries = null;
65
66   protected FTSRestClient()
67   {
68
69   }
70
71   public void parseDataColumnsConfigFile()
72   {
73     String fileName = getColumnDataConfigFileName();
74
75     InputStream in = getClass().getResourceAsStream(fileName);
76
77     try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) 
78     {
79       String line;
80       while ((line = br.readLine()) != null)
81       {
82         final String[] lineData = line.split(";");
83         try
84         {
85           if (lineData.length == 2)
86           {
87             if (lineData[0].equalsIgnoreCase("_data_column.primary_key"))
88             {
89               primaryKeyColumnCode = lineData[1];
90             }
91             if (lineData[0].equalsIgnoreCase(
92                     "_data_column.default_response_page_size"))
93             {
94               defaultResponsePageSize = Integer.valueOf(lineData[1]);
95             }
96           }
97           else if (lineData.length == 3)
98           {
99             dataColumnGroups.add(new FTSDataColumnGroupI()
100             {
101               @Override
102               public String getID()
103               {
104                 return lineData[0];
105               }
106
107               @Override
108               public String getName()
109               {
110                 return lineData[1];
111               }
112
113               @Override
114               public int getSortOrder()
115               {
116                 return Integer.valueOf(lineData[2]);
117               }
118
119               @Override
120               public String toString()
121               {
122                 return lineData[1];
123               }
124
125               @Override
126               public int hashCode()
127               {
128                 return Objects.hash(this.getID(), this.getName(),
129                         this.getSortOrder());
130               }
131
132               @Override
133               public boolean equals(Object otherObject)
134               {
135                 FTSDataColumnGroupI that = (FTSDataColumnGroupI) otherObject;
136                 return this.getID().equals(that.getID())
137                         && this.getName().equals(that.getName())
138                         && this.getSortOrder() == that.getSortOrder();
139               }
140             });
141           }
142           else if (lineData.length > 6)
143           {
144             FTSDataColumnI dataCol = new FTSDataColumnI()
145             {
146               @Override
147               public String toString()
148               {
149                 return lineData[0];
150               }
151
152               @Override
153               public String getName()
154               {
155                 return lineData[0];
156               }
157
158               @Override
159               public String getCode()
160               {
161                 return lineData[1].split("\\|")[0];
162               }
163
164               @Override
165               public String getAltCode()
166               {
167                 return lineData[1].split("\\|").length > 1
168                         ? lineData[1].split("\\|")[1]
169                         : getCode();
170               }
171
172               @Override
173               public DataTypeI getDataType()
174               {
175                 final String[] dataTypeString = lineData[2].split("\\|");
176                 final String classString = dataTypeString[0].toUpperCase(Locale.ROOT);
177
178                 return new DataTypeI()
179                 {
180
181                   @Override
182                   public boolean isFormtted()
183                   {
184                     if (dataTypeString.length > 1
185                             && dataTypeString[1] != null)
186                     {
187                       switch (dataTypeString[1].toUpperCase(Locale.ROOT))
188                       {
189                       case "T":
190                       case "TRUE":
191                         return true;
192                       case "F":
193                       case "False":
194                       default:
195                         return false;
196                       }
197                     }
198                     return false;
199                   }
200
201                   @Override
202                   public int getSignificantFigures()
203                   {
204                     if (dataTypeString.length > 2
205                             && dataTypeString[2] != null)
206                     {
207                       return Integer.valueOf(dataTypeString[2]);
208                     }
209                     return 0;
210                   }
211
212                   @Override
213                   public Class getDataTypeClass()
214                   {
215                     switch (classString)
216                     {
217                     case "INT":
218                     case "INTEGER":
219                       return Integer.class;
220                     case "DOUBLE":
221                       return Double.class;
222                     case "STRING":
223                     default:
224                       return String.class;
225                     }
226                   }
227                 };
228
229               }
230
231               @Override
232               public FTSDataColumnGroupI getGroup()
233               {
234                 FTSDataColumnGroupI group = null;
235                 try
236                 {
237                   group = getDataColumnGroupById(lineData[3]);
238                 } catch (Exception e)
239                 {
240                   e.printStackTrace();
241                 }
242                 return group;
243               }
244
245               @Override
246               public int getMinWidth()
247               {
248                 return Integer.valueOf(lineData[4]);
249               }
250
251               @Override
252               public int getMaxWidth()
253               {
254                 return Integer.valueOf(lineData[5]);
255               }
256
257               @Override
258               public int getPreferredWidth()
259               {
260                 return Integer.valueOf(lineData[6]);
261               }
262
263               @Override
264               public boolean isPrimaryKeyColumn()
265               {
266                 return getName().equalsIgnoreCase(primaryKeyColumnCode)
267                         || getCode().equalsIgnoreCase(primaryKeyColumnCode);
268               }
269
270               @Override
271               public boolean isVisibleByDefault()
272               {
273                 return Boolean.valueOf(lineData[7]);
274               }
275
276               @Override
277               public boolean isSearchable()
278               {
279                 return Boolean.valueOf(lineData[8]);
280               }
281
282               @Override
283               public int hashCode()
284               {
285                 return Objects.hash(this.getName(), this.getCode(),
286                         this.getGroup());
287               }
288
289               @Override
290               public boolean equals(Object otherObject)
291               {
292                 FTSDataColumnI that = (FTSDataColumnI) otherObject;
293                 return otherObject == null ? false
294                         : this.getCode().equals(that.getCode())
295                         && this.getName().equals(that.getName())
296                         && this.getGroup().equals(that.getGroup());
297               }
298
299             };
300             dataColumns.add(dataCol);
301
302             if (dataCol.isSearchable())
303             {
304               searchableDataColumns.add(dataCol);
305             }
306
307             if (dataCol.isVisibleByDefault())
308             {
309               defaulDisplayedDataColumns.add(dataCol);
310             }
311
312           }
313           else
314           {
315             continue;
316           }
317         } catch (Exception e)
318         {
319           e.printStackTrace();
320         }
321       }
322       try
323       {
324         this.primaryKeyColumn = getDataColumnByNameOrCode(
325                 primaryKeyColumnCode);
326       } catch (Exception e)
327       {
328         e.printStackTrace();
329       }
330     } catch (IOException e)
331     {
332       e.printStackTrace();
333     }
334   }
335
336   @Override
337   public int getPrimaryKeyColumIndex(
338           Collection<FTSDataColumnI> wantedFields, boolean hasRefSeq)
339           throws Exception
340   {
341
342     // If a reference sequence is attached then start counting from 1 else
343     // start from zero
344     int pdbFieldIndexCounter = hasRefSeq ? 1 : 0;
345
346     for (FTSDataColumnI field : wantedFields)
347     {
348       if (field.isPrimaryKeyColumn())
349       {
350         break; // Once PDB Id index is determined exit iteration
351       }
352       ++pdbFieldIndexCounter;
353     }
354     return pdbFieldIndexCounter;
355   }
356
357   @Override
358   public String getDataColumnsFieldsAsCommaDelimitedString(
359           Collection<FTSDataColumnI> dataColumnFields)
360   {
361     String result = "";
362     if (dataColumnFields != null && !dataColumnFields.isEmpty())
363     {
364       StringBuilder returnedFields = new StringBuilder();
365       for (FTSDataColumnI field : dataColumnFields)
366       {
367         returnedFields.append(",").append(field.getCode());
368       }
369       returnedFields.deleteCharAt(0);
370       result = returnedFields.toString();
371     }
372     return result;
373   }
374
375   @Override
376   public Collection<FTSDataColumnI> getAllFTSDataColumns()
377   {
378     if (dataColumns == null || dataColumns.isEmpty())
379     {
380       parseDataColumnsConfigFile();
381     }
382     return dataColumns;
383   }
384
385   @Override
386   public Collection<FTSDataColumnI> getSearchableDataColumns()
387   {
388     if (searchableDataColumns == null || searchableDataColumns.isEmpty())
389     {
390       parseDataColumnsConfigFile();
391     }
392     return searchableDataColumns;
393   }
394
395   @Override
396   public Collection<FTSDataColumnI> getAllDefaultDisplayedFTSDataColumns()
397   {
398     if (defaulDisplayedDataColumns == null
399             || defaulDisplayedDataColumns.isEmpty())
400     {
401       parseDataColumnsConfigFile();
402     }
403     return defaulDisplayedDataColumns;
404   }
405
406   @Override
407   public FTSDataColumnI getPrimaryKeyColumn()
408   {
409     if (defaulDisplayedDataColumns == null
410             || defaulDisplayedDataColumns.isEmpty())
411     {
412       parseDataColumnsConfigFile();
413     }
414     return primaryKeyColumn;
415   }
416
417   @Override
418   public FTSDataColumnI getDataColumnByNameOrCode(String nameOrCode)
419           throws Exception
420   {
421     if (dataColumns == null || dataColumns.isEmpty())
422     {
423       parseDataColumnsConfigFile();
424     }
425     for (FTSDataColumnI column : dataColumns)
426     {
427       if (column.getName().equalsIgnoreCase(nameOrCode)
428               || column.getCode().equalsIgnoreCase(nameOrCode))
429       {
430         return column;
431       }
432     }
433     throw new Exception(
434             "Couldn't find data column with name : " + nameOrCode);
435   }
436
437   /**
438    * 
439    * @param instance
440    * @param mocks {{working query, working response}, ...}
441    */
442   public static void createMockFTSRestClient(FTSRestClient instance,String[][] mocks)
443   {
444     instance.setMock(mocks);
445   }
446
447   @Override
448   public FTSDataColumnGroupI getDataColumnGroupById(String id)
449           throws Exception
450   {
451     if (dataColumns == null || dataColumns.isEmpty())
452     {
453       parseDataColumnsConfigFile();
454     }
455     for (FTSDataColumnGroupI columnGroup : dataColumnGroups)
456     {
457       if (columnGroup.getID().equalsIgnoreCase(id))
458       {
459         return columnGroup;
460       }
461     }
462     throw new Exception("Couldn't find data column group with id : " + id);
463   }
464
465   public static String getMessageByHTTPStatusCode(int code, String service)
466   {
467     String message = "";
468     switch (code)
469     {
470     case 400:
471       message = "Bad request. There is a problem with your input.";
472       break;
473
474     case 410:
475       message = service + " rest services no longer available!";
476       break;
477     case 403:
478     case 404:
479       message = "The requested resource could not be found";
480       break;
481     case 408:
482     case 409:
483     case 500:
484     case 501:
485     case 502:
486     case 504:
487     case 505:
488       message = "There seems to be an error from the " + service
489               + " server";
490       break;
491     case 503:
492       message = "Service not available. The server is being updated, try again later.";
493       break;
494     default:
495       break;
496     }
497     return String.valueOf(code) + " " + message;
498   }
499
500   public static void unMock(FTSRestClient instance)
501   {
502     instance.mockQueries=null;
503   }
504
505   protected String getResourceFile(String fileName)
506   {
507     String result = "";
508     try
509     {
510       result = getClass().getResource(fileName).getFile();
511     } catch (Exception e)
512     {
513       e.printStackTrace();
514     }
515     return result;
516
517   }
518
519   @Override
520   public int getDefaultResponsePageSize()
521   {
522     if (dataColumns == null || dataColumns.isEmpty())
523     {
524       parseDataColumnsConfigFile();
525     }
526     return defaultResponsePageSize;
527   }
528
529   protected void setMock(String[][] mocks)
530   {
531     if (mocks==null) {
532       mockQueries=null;
533       return;
534     }
535     mockQueries=new HashMap<String,String>();
536     for (String[] mock:mocks)
537     {
538       mockQueries.put(mock[0],mock[1]);
539     }
540   }
541
542   protected boolean isMocked()
543   {
544     return mockQueries!=null;
545   }
546
547   @Override
548   public String[] getPreferencesColumnsFor(PreferenceSource source)
549   {
550     String[] columnNames = null;
551     switch (source)
552     {
553     case SEARCH_SUMMARY:
554       columnNames = new String[] { "", "Display", "Group" };
555       break;
556     default:
557       // non structure sources don't return any other kind of preferences columns
558       break;
559     }
560     return columnNames;
561   }
562 }