b262f64a1922b9bb896ef455926f6b1329e89dfc
[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.Objects;
30
31 import jalview.fts.api.FTSDataColumnI;
32 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
33 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
34 import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
35 import jalview.fts.api.FTSRestClientI;
36
37 /**
38  * Base class providing implementation for common methods defined in
39  * FTSRestClientI
40  * 
41  * @author tcnofoegbu
42  * 
43  * @note implementations MUST be accessed as a singleton.
44  */
45 public abstract class FTSRestClient implements FTSRestClientI
46 {
47   protected Collection<FTSDataColumnI> dataColumns = new ArrayList<>();
48
49   protected Collection<FTSDataColumnGroupI> dataColumnGroups = new ArrayList<>();
50
51   protected Collection<FTSDataColumnI> searchableDataColumns = new ArrayList<>();
52
53   protected Collection<FTSDataColumnI> defaulDisplayedDataColumns = new ArrayList<>();
54
55   protected FTSDataColumnI primaryKeyColumn;
56
57   private String primaryKeyColumnCode = null;
58
59   private int defaultResponsePageSize = 100;
60
61   protected String mockQuery = null;
62
63   protected String mockResponse = null;
64
65   protected FTSRestClient()
66   {
67
68   }
69
70   public void parseDataColumnsConfigFile()
71   {
72     String fileName = getColumnDataConfigFileName();
73
74     InputStream in = getClass().getResourceAsStream(fileName);
75
76     try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) 
77     {
78       String line;
79       while ((line = br.readLine()) != null)
80       {
81         final String[] lineData = line.split(";");
82         try
83         {
84           if (lineData.length == 2)
85           {
86             if (lineData[0].equalsIgnoreCase("_data_column.primary_key"))
87             {
88               primaryKeyColumnCode = lineData[1];
89             }
90             if (lineData[0].equalsIgnoreCase(
91                     "_data_column.default_response_page_size"))
92             {
93               defaultResponsePageSize = Integer.valueOf(lineData[1]);
94             }
95           }
96           else if (lineData.length == 3)
97           {
98             dataColumnGroups.add(new FTSDataColumnGroupI()
99             {
100               @Override
101               public String getID()
102               {
103                 return lineData[0];
104               }
105
106               @Override
107               public String getName()
108               {
109                 return lineData[1];
110               }
111
112               @Override
113               public int getSortOrder()
114               {
115                 return Integer.valueOf(lineData[2]);
116               }
117
118               @Override
119               public String toString()
120               {
121                 return lineData[1];
122               }
123
124               @Override
125               public int hashCode()
126               {
127                 return Objects.hash(this.getID(), this.getName(),
128                         this.getSortOrder());
129               }
130
131               @Override
132               public boolean equals(Object otherObject)
133               {
134                 FTSDataColumnGroupI that = (FTSDataColumnGroupI) otherObject;
135                 return this.getID().equals(that.getID())
136                         && this.getName().equals(that.getName())
137                         && this.getSortOrder() == that.getSortOrder();
138               }
139             });
140           }
141           else if (lineData.length > 6)
142           {
143             FTSDataColumnI dataCol = new FTSDataColumnI()
144             {
145               @Override
146               public String toString()
147               {
148                 return lineData[0];
149               }
150
151               @Override
152               public String getName()
153               {
154                 return lineData[0];
155               }
156
157               @Override
158               public String getCode()
159               {
160                 return lineData[1].split("\\|")[0];
161               }
162
163               @Override
164               public String getAltCode()
165               {
166                 return lineData[1].split("\\|").length > 1
167                         ? lineData[1].split("\\|")[1]
168                         : getCode();
169               }
170
171               @Override
172               public DataTypeI getDataType()
173               {
174                 final String[] dataTypeString = lineData[2].split("\\|");
175                 final String classString = dataTypeString[0].toUpperCase();
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())
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   public static void createMockFTSRestClient(FTSRestClient instance,String workingQuery,
437           String jsonResponse)
438   {
439     instance.setMock(workingQuery,jsonResponse);
440   }
441
442   @Override
443   public FTSDataColumnGroupI getDataColumnGroupById(String id)
444           throws Exception
445   {
446     if (dataColumns == null || dataColumns.isEmpty())
447     {
448       parseDataColumnsConfigFile();
449     }
450     for (FTSDataColumnGroupI columnGroup : dataColumnGroups)
451     {
452       if (columnGroup.getID().equalsIgnoreCase(id))
453       {
454         return columnGroup;
455       }
456     }
457     throw new Exception("Couldn't find data column group with id : " + id);
458   }
459
460   public static String getMessageByHTTPStatusCode(int code, String service)
461   {
462     String message = "";
463     switch (code)
464     {
465     case 400:
466       message = "Bad request. There is a problem with your input.";
467       break;
468
469     case 410:
470       message = service + " rest services no longer available!";
471       break;
472     case 403:
473     case 404:
474       message = "The requested resource could not be found";
475       break;
476     case 408:
477     case 409:
478     case 500:
479     case 501:
480     case 502:
481     case 504:
482     case 505:
483       message = "There seems to be an error from the " + service
484               + " server";
485       break;
486     case 503:
487       message = "Service not available. The server is being updated, try again later.";
488       break;
489     default:
490       break;
491     }
492     return String.valueOf(code) + " " + message;
493   }
494
495   public static void unMock(FTSRestClient instance)
496   {
497     instance.mockQuery =null;
498     instance.mockResponse =null;
499   }
500
501   protected String getResourceFile(String fileName)
502   {
503     String result = "";
504     try
505     {
506       result = getClass().getResource(fileName).getFile();
507     } catch (Exception e)
508     {
509       e.printStackTrace();
510     }
511     return result;
512
513   }
514
515   @Override
516   public int getDefaultResponsePageSize()
517   {
518     if (dataColumns == null || dataColumns.isEmpty())
519     {
520       parseDataColumnsConfigFile();
521     }
522     return defaultResponsePageSize;
523   }
524
525   protected void setMock(String workingQuery, String jsonResponse)
526   {
527     mockQuery=workingQuery;
528     mockResponse = jsonResponse;
529   }
530
531   protected boolean isMocked()
532   {
533     return mockQuery != null && mockResponse!=null;
534   }
535
536   @Override
537   public String[] getPreferencesColumnsFor(PreferenceSource source)
538   {
539     String[] columnNames = null;
540     switch (source)
541     {
542     case SEARCH_SUMMARY:
543       columnNames = new String[] { "", "Display", "Group" };
544       break;
545     default:
546       // non structure sources don't return any other kind of preferences columns
547       break;
548     }
549     return columnNames;
550   }
551 }