ac5b2806519e9db4a0f5b11b53baca346ec81ea3
[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]
177                         .toUpperCase(Locale.ROOT);
178
179                 return new DataTypeI()
180                 {
181
182                   @Override
183                   public boolean isFormtted()
184                   {
185                     if (dataTypeString.length > 1
186                             && dataTypeString[1] != null)
187                     {
188                       switch (dataTypeString[1].toUpperCase(Locale.ROOT))
189                       {
190                       case "T":
191                       case "TRUE":
192                         return true;
193                       case "F":
194                       case "False":
195                       default:
196                         return false;
197                       }
198                     }
199                     return false;
200                   }
201
202                   @Override
203                   public int getSignificantFigures()
204                   {
205                     if (dataTypeString.length > 2
206                             && dataTypeString[2] != null)
207                     {
208                       return Integer.valueOf(dataTypeString[2]);
209                     }
210                     return 0;
211                   }
212
213                   @Override
214                   public Class getDataTypeClass()
215                   {
216                     switch (classString)
217                     {
218                     case "INT":
219                     case "INTEGER":
220                       return Integer.class;
221                     case "DOUBLE":
222                       return Double.class;
223                     case "STRING":
224                     default:
225                       return String.class;
226                     }
227                   }
228                 };
229
230               }
231
232               @Override
233               public FTSDataColumnGroupI getGroup()
234               {
235                 FTSDataColumnGroupI group = null;
236                 try
237                 {
238                   group = getDataColumnGroupById(lineData[3]);
239                 } catch (Exception e)
240                 {
241                   e.printStackTrace();
242                 }
243                 return group;
244               }
245
246               @Override
247               public int getMinWidth()
248               {
249                 return Integer.valueOf(lineData[4]);
250               }
251
252               @Override
253               public int getMaxWidth()
254               {
255                 return Integer.valueOf(lineData[5]);
256               }
257
258               @Override
259               public int getPreferredWidth()
260               {
261                 return Integer.valueOf(lineData[6]);
262               }
263
264               @Override
265               public boolean isPrimaryKeyColumn()
266               {
267                 return getName().equalsIgnoreCase(primaryKeyColumnCode)
268                         || getCode().equalsIgnoreCase(primaryKeyColumnCode);
269               }
270
271               @Override
272               public boolean isVisibleByDefault()
273               {
274                 return Boolean.valueOf(lineData[7]);
275               }
276
277               @Override
278               public boolean isSearchable()
279               {
280                 return Boolean.valueOf(lineData[8]);
281               }
282
283               @Override
284               public int hashCode()
285               {
286                 return Objects.hash(this.getName(), this.getCode(),
287                         this.getGroup());
288               }
289
290               @Override
291               public boolean equals(Object otherObject)
292               {
293                 FTSDataColumnI that = (FTSDataColumnI) otherObject;
294                 return otherObject == null ? false
295                         : this.getCode().equals(that.getCode())
296                                 && this.getName().equals(that.getName())
297                                 && this.getGroup().equals(that.getGroup());
298               }
299
300             };
301             dataColumns.add(dataCol);
302
303             if (dataCol.isSearchable())
304             {
305               searchableDataColumns.add(dataCol);
306             }
307
308             if (dataCol.isVisibleByDefault())
309             {
310               defaulDisplayedDataColumns.add(dataCol);
311             }
312
313           }
314           else
315           {
316             continue;
317           }
318         } catch (Exception e)
319         {
320           e.printStackTrace();
321         }
322       }
323       try
324       {
325         this.primaryKeyColumn = getDataColumnByNameOrCode(
326                 primaryKeyColumnCode);
327       } catch (Exception e)
328       {
329         e.printStackTrace();
330       }
331     } catch (IOException e)
332     {
333       e.printStackTrace();
334     }
335   }
336
337   @Override
338   public int getPrimaryKeyColumIndex(
339           Collection<FTSDataColumnI> wantedFields, boolean hasRefSeq)
340           throws Exception
341   {
342
343     // If a reference sequence is attached then start counting from 1 else
344     // start from zero
345     int pdbFieldIndexCounter = hasRefSeq ? 1 : 0;
346
347     for (FTSDataColumnI field : wantedFields)
348     {
349       if (field.isPrimaryKeyColumn())
350       {
351         break; // Once PDB Id index is determined exit iteration
352       }
353       ++pdbFieldIndexCounter;
354     }
355     return pdbFieldIndexCounter;
356   }
357
358   @Override
359   public String getDataColumnsFieldsAsCommaDelimitedString(
360           Collection<FTSDataColumnI> dataColumnFields)
361   {
362     String result = "";
363     if (dataColumnFields != null && !dataColumnFields.isEmpty())
364     {
365       StringBuilder returnedFields = new StringBuilder();
366       for (FTSDataColumnI field : dataColumnFields)
367       {
368         returnedFields.append(",").append(field.getCode());
369       }
370       returnedFields.deleteCharAt(0);
371       result = returnedFields.toString();
372     }
373     return result;
374   }
375
376   @Override
377   public Collection<FTSDataColumnI> getAllFTSDataColumns()
378   {
379     if (dataColumns == null || dataColumns.isEmpty())
380     {
381       parseDataColumnsConfigFile();
382     }
383     return dataColumns;
384   }
385
386   @Override
387   public Collection<FTSDataColumnI> getSearchableDataColumns()
388   {
389     if (searchableDataColumns == null || searchableDataColumns.isEmpty())
390     {
391       parseDataColumnsConfigFile();
392     }
393     return searchableDataColumns;
394   }
395
396   @Override
397   public Collection<FTSDataColumnI> getAllDefaultDisplayedFTSDataColumns()
398   {
399     if (defaulDisplayedDataColumns == null
400             || defaulDisplayedDataColumns.isEmpty())
401     {
402       parseDataColumnsConfigFile();
403     }
404     return defaulDisplayedDataColumns;
405   }
406
407   @Override
408   public FTSDataColumnI getPrimaryKeyColumn()
409   {
410     if (defaulDisplayedDataColumns == null
411             || defaulDisplayedDataColumns.isEmpty())
412     {
413       parseDataColumnsConfigFile();
414     }
415     return primaryKeyColumn;
416   }
417
418   @Override
419   public FTSDataColumnI getDataColumnByNameOrCode(String nameOrCode)
420           throws Exception
421   {
422     if (dataColumns == null || dataColumns.isEmpty())
423     {
424       parseDataColumnsConfigFile();
425     }
426     for (FTSDataColumnI column : dataColumns)
427     {
428       if (column.getName().equalsIgnoreCase(nameOrCode)
429               || column.getCode().equalsIgnoreCase(nameOrCode))
430       {
431         return column;
432       }
433     }
434     throw new Exception(
435             "Couldn't find data column with name : " + nameOrCode);
436   }
437
438   /**
439    * 
440    * @param instance
441    * @param mocks
442    *          {{working query, working response}, ...}
443    */
444   public static void createMockFTSRestClient(FTSRestClient instance,
445           String[][] mocks)
446   {
447     instance.setMock(mocks);
448   }
449
450   @Override
451   public FTSDataColumnGroupI getDataColumnGroupById(String id)
452           throws Exception
453   {
454     if (dataColumns == null || dataColumns.isEmpty())
455     {
456       parseDataColumnsConfigFile();
457     }
458     for (FTSDataColumnGroupI columnGroup : dataColumnGroups)
459     {
460       if (columnGroup.getID().equalsIgnoreCase(id))
461       {
462         return columnGroup;
463       }
464     }
465     throw new Exception("Couldn't find data column group with id : " + id);
466   }
467
468   public static String getMessageByHTTPStatusCode(int code, String service)
469   {
470     String message = "";
471     switch (code)
472     {
473     case 400:
474       message = "Bad request. There is a problem with your input.";
475       break;
476
477     case 410:
478       message = service + " rest services no longer available!";
479       break;
480     case 403:
481     case 404:
482       message = "The requested resource could not be found";
483       break;
484     case 408:
485     case 409:
486     case 500:
487     case 501:
488     case 502:
489     case 504:
490     case 505:
491       message = "There seems to be an error from the " + service
492               + " server";
493       break;
494     case 503:
495       message = "Service not available. The server is being updated, try again later.";
496       break;
497     default:
498       break;
499     }
500     return String.valueOf(code) + " " + message;
501   }
502
503   public static void unMock(FTSRestClient instance)
504   {
505     instance.mockQueries = null;
506   }
507
508   protected String getResourceFile(String fileName)
509   {
510     String result = "";
511     try
512     {
513       result = getClass().getResource(fileName).getFile();
514     } catch (Exception e)
515     {
516       e.printStackTrace();
517     }
518     return result;
519
520   }
521
522   @Override
523   public int getDefaultResponsePageSize()
524   {
525     if (dataColumns == null || dataColumns.isEmpty())
526     {
527       parseDataColumnsConfigFile();
528     }
529     return defaultResponsePageSize;
530   }
531
532   protected void setMock(String[][] mocks)
533   {
534     if (mocks == null)
535     {
536       mockQueries = null;
537       return;
538     }
539     mockQueries = new HashMap<String, String>();
540     for (String[] mock : mocks)
541     {
542       mockQueries.put(mock[0], mock[1]);
543     }
544   }
545
546   protected boolean isMocked()
547   {
548     return mockQueries != null;
549   }
550
551   @Override
552   public String[] getPreferencesColumnsFor(PreferenceSource source)
553   {
554     String[] columnNames = null;
555     switch (source)
556     {
557     case SEARCH_SUMMARY:
558       columnNames = new String[] { "", "Display", "Group" };
559       break;
560     default:
561       // non structure sources don't return any other kind of preferences
562       // columns
563       break;
564     }
565     return columnNames;
566   }
567 }