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