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