2d79432cf2db016c5017209d308e727c891510db
[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 "ALL".equals(getName()) ? getName()
148                         : getName() + " [" + getAltCode() + "]";
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]
176                         .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
441    *          {{working query, working response}, ...}
442    */
443   public static void createMockFTSRestClient(FTSRestClient instance,
444           String[][] mocks)
445   {
446     instance.setMock(mocks);
447   }
448
449   @Override
450   public FTSDataColumnGroupI getDataColumnGroupById(String id)
451           throws Exception
452   {
453     if (dataColumns == null || dataColumns.isEmpty())
454     {
455       parseDataColumnsConfigFile();
456     }
457     for (FTSDataColumnGroupI columnGroup : dataColumnGroups)
458     {
459       if (columnGroup.getID().equalsIgnoreCase(id))
460       {
461         return columnGroup;
462       }
463     }
464     throw new Exception("Couldn't find data column group with id : " + id);
465   }
466
467   public static String getMessageByHTTPStatusCode(int code, String service)
468   {
469     String message = "";
470     switch (code)
471     {
472     case 400:
473       message = "Bad request. There is a problem with your input.";
474       break;
475
476     case 410:
477       message = service + " rest services no longer available!";
478       break;
479     case 403:
480     case 404:
481       message = "The requested resource could not be found";
482       break;
483     case 408:
484     case 409:
485     case 500:
486     case 501:
487     case 502:
488     case 504:
489     case 505:
490       message = "There seems to be an error from the " + service
491               + " server";
492       break;
493     case 503:
494       message = "Service not available. The server is being updated, try again later.";
495       break;
496     default:
497       break;
498     }
499     return String.valueOf(code) + " " + message;
500   }
501
502   public static void unMock(FTSRestClient instance)
503   {
504     instance.mockQueries = null;
505   }
506
507   protected String getResourceFile(String fileName)
508   {
509     String result = "";
510     try
511     {
512       result = getClass().getResource(fileName).getFile();
513     } catch (Exception e)
514     {
515       e.printStackTrace();
516     }
517     return result;
518
519   }
520
521   @Override
522   public int getDefaultResponsePageSize()
523   {
524     if (dataColumns == null || dataColumns.isEmpty())
525     {
526       parseDataColumnsConfigFile();
527     }
528     return defaultResponsePageSize;
529   }
530
531   protected void setMock(String[][] mocks)
532   {
533     if (mocks == null)
534     {
535       mockQueries = null;
536       return;
537     }
538     mockQueries = new HashMap<String, String>();
539     for (String[] mock : mocks)
540     {
541       mockQueries.put(mock[0], mock[1]);
542     }
543   }
544
545   protected boolean isMocked()
546   {
547     return mockQueries != null;
548   }
549
550   @Override
551   public String[] getPreferencesColumnsFor(PreferenceSource source)
552   {
553     String[] columnNames = null;
554     switch (source)
555     {
556     case SEARCH_SUMMARY:
557       columnNames = new String[] { "", "Display", "Group" };
558       break;
559     default:
560       // non structure sources don't return any other kind of preferences
561       // columns
562       break;
563     }
564     return columnNames;
565   }
566 }