JAL-3829 upgrade Jmol to 14.31.53, SwingJS-JSMol to 14.31.54 and SwingJS to 3.3.1
[jalview.git] / src / jalview / fts / service / threedbeacons / TDBeaconsFTSRestClient.java
1 package jalview.fts.service.threedbeacons;
2
3 import java.net.URI;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Objects;
10
11 import javax.ws.rs.core.MediaType;
12
13 import org.json.simple.parser.ParseException;
14
15 import com.sun.jersey.api.client.Client;
16 import com.sun.jersey.api.client.ClientResponse;
17 import com.sun.jersey.api.client.WebResource;
18 import com.sun.jersey.api.client.config.DefaultClientConfig;
19
20 import jalview.datamodel.SequenceI;
21 import jalview.fts.api.FTSData;
22 import jalview.fts.api.FTSDataColumnI;
23 import jalview.fts.api.FTSRestClientI;
24 import jalview.fts.api.StructureFTSRestClientI;
25 import jalview.fts.core.FTSRestClient;
26 import jalview.fts.core.FTSRestRequest;
27 import jalview.fts.core.FTSRestResponse;
28 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
29 import jalview.fts.service.pdb.PDBFTSRestClient;
30 import jalview.util.JSONUtils;
31 import jalview.util.MessageManager;
32 import jalview.util.Platform;
33
34 public class TDBeaconsFTSRestClient extends FTSRestClient
35         implements StructureFTSRestClientI
36 {
37   /**
38    * production server URI
39    */
40   private static String TDB_PROD_API="https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/";
41   /**
42    * dev server URI
43    */
44   private static String TDB_DEV_API="https://wwwdev.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/";
45   private static String DEFAULT_THREEDBEACONS_DOMAIN = TDB_PROD_API; 
46
47   public static FTSRestClientI instance = null;
48
49   protected TDBeaconsFTSRestClient()
50   {
51   }
52   @SuppressWarnings("unchecked")
53   @Override
54   public FTSRestResponse executeRequest(FTSRestRequest tdbRestRequest)
55           throws Exception
56   {
57     try
58     {
59       String query = tdbRestRequest.getSearchTerm();
60       Client client;
61       Class<ClientResponse> clientResponseClass;
62       if (Platform.isJS())
63       {
64         // JavaScript only
65         client = (Client) (Object) new jalview.javascript.web.Client();
66         clientResponseClass = (Class<ClientResponse>) (Object) jalview.javascript.web.ClientResponse.class;
67       }
68       else
69       /**
70        * Java only
71        * 
72        * @j2sIgnore
73        */
74       {
75         client = Client.create(new DefaultClientConfig());
76         clientResponseClass = ClientResponse.class;
77       }
78       WebResource webResource;
79       webResource = client.resource(DEFAULT_THREEDBEACONS_DOMAIN)
80               .path(query);
81       URI uri = webResource.getURI();
82       System.out.println(uri.toString());
83
84       // Execute the REST request
85       ClientResponse clientResponse;
86       if (isMocked()) { 
87         clientResponse = null;
88       }
89       else
90       {
91         clientResponse = webResource.accept(MediaType.APPLICATION_JSON)
92                 .get(clientResponseClass);
93       }
94
95       // Get the JSON string from the response object or directly from the
96       // client (JavaScript)
97       Map<String, Object> jsonObj = null;
98       String responseString = null;
99
100       // Check the response status and report exception if one occurs
101       int responseStatus = isMocked() ? (mockQuery.equals(query) ? 200 : 404) : clientResponse.getStatus();
102       switch (responseStatus)
103       {
104       // if success
105       case 200:
106         if (Platform.isJS())
107         {
108           jsonObj = clientResponse.getEntity(Map.class);
109         }
110         else
111         {
112           responseString = isMocked() ? mockResponse: clientResponse.getEntity(String.class);
113         }
114         break;
115       case 400:
116         throw new Exception(parseJsonExceptionString(responseString));
117       case 404:
118         return emptyTDBeaconsJsonResponse();
119       default:
120         throw new Exception(
121                 getMessageByHTTPStatusCode(responseStatus, "3DBeacons"));
122       }
123       // Process the response and return the result to the caller.
124       return parseTDBeaconsJsonResponse(responseString, jsonObj,
125               tdbRestRequest);
126     } catch (Exception e)
127     {
128       String exceptionMsg = e.getMessage();
129       if (exceptionMsg.contains("SocketException"))
130       {
131         // No internet connection
132         throw new Exception(MessageManager.getString(
133                 "exception.unable_to_detect_internet_connection"));
134       }
135       else if (exceptionMsg.contains("UnknownHostException"))
136       {
137         // The server is unreachable
138         throw new Exception(MessageManager.formatMessage(
139                 "exception.fts_server_unreachable", "3DB Hub"));
140       }
141       else
142       {
143         throw e;
144       }
145     }
146
147   }
148
149   /**
150    * returns response for when the 3D-Beacons service doesn't have a record for
151    * the given query - in 2.11.2 this triggers a failover to the PDBe FTS 
152    * 
153    * @return null
154    */
155   private FTSRestResponse emptyTDBeaconsJsonResponse()
156   {
157     return null;
158   }
159
160   public String setSearchTerm(String term)
161   {
162     return term;
163   }
164
165   public static FTSRestResponse parseTDBeaconsJsonResponse(
166           String tdbJsonResponseString, FTSRestRequest tdbRestRequest)
167   {
168     return parseTDBeaconsJsonResponse(tdbJsonResponseString,
169             (Map<String, Object>) null, tdbRestRequest);
170   }
171
172   @SuppressWarnings("unchecked")
173   public static FTSRestResponse parseTDBeaconsJsonResponse(
174           String tdbJsonResponseString, Map<String, Object> jsonObj,
175           FTSRestRequest tdbRestRequest)
176   {
177     FTSRestResponse searchResult = new FTSRestResponse();
178     List<FTSData> result = null;
179
180     try
181     {
182       if (jsonObj == null)
183       {
184         jsonObj = (Map<String, Object>) JSONUtils
185                 .parse(tdbJsonResponseString);
186       }
187
188       Object uniprot_entry = jsonObj.get("uniprot_entry");
189       // TODO: decide if anything from uniprot_entry needs to be reported via
190       // the FTSRestResponse object
191       // Arnaud added seqLength = (Long) ((Map<String, Object>)
192       // jsonObj.get("uniprot_entry")).get("sequence_length");
193
194       List<Object> structures = (List<Object>) jsonObj.get("structures");
195       result = new ArrayList<>();
196
197       int numFound = 0;
198       for (Iterator<Object> strucIter = structures.iterator(); strucIter
199               .hasNext();)
200       {
201         Map<String, Object> structure = (Map<String, Object>) strucIter
202                 .next();
203         result.add(getFTSData(structure, tdbRestRequest));
204         numFound++;
205       }
206
207       searchResult.setNumberOfItemsFound(numFound);
208       searchResult.setSearchSummary(result);
209
210     } catch (ParseException e)
211     {
212       e.printStackTrace();
213     }
214     return searchResult;
215   }
216
217   private static FTSData getFTSData(Map<String, Object> tdbJsonStructure,
218           FTSRestRequest tdbRequest)
219   {
220     // TODO: consider reusing PDBFTSRestClient.getFTSData ?
221
222     String primaryKey = null;
223     Object[] summaryRowData;
224
225     SequenceI associatedSequence;
226
227     Collection<FTSDataColumnI> displayFields = tdbRequest.getWantedFields();
228     SequenceI associatedSeq = tdbRequest.getAssociatedSequence();
229     int colCounter = 0;
230     summaryRowData = new Object[(associatedSeq != null)
231                                 ? displayFields.size() + 1
232                                 : displayFields.size()];
233                         if (associatedSeq != null)
234                         {
235                           associatedSequence = associatedSeq;
236                           summaryRowData[0] = associatedSequence;
237                           colCounter = 1;
238                         }
239
240     for (FTSDataColumnI field : displayFields)
241     {
242       String fieldData = (tdbJsonStructure.get(field.getCode()) == null)
243               ? " "
244               : tdbJsonStructure.get(field.getCode()).toString();
245       // System.out.println("Field : " + field + " Data : " + fieldData);
246       if (field.isPrimaryKeyColumn())
247       {
248         primaryKey = fieldData;
249         summaryRowData[colCounter++] = primaryKey;
250       }
251       else if (fieldData == null || fieldData.trim().isEmpty())
252       {
253         summaryRowData[colCounter++] = null;
254       }
255       else
256       {
257         try
258         {
259           summaryRowData[colCounter++] = (field.getDataType()
260                   .getDataTypeClass() == Integer.class)
261                           ? Integer.valueOf(fieldData)
262                           : (field.getDataType()
263                                   .getDataTypeClass() == Double.class)
264                                           ? Double.valueOf(fieldData)
265                                           : fieldData;
266         } catch (Exception e)
267         {
268           // e.printStackTrace();
269           System.out.println("offending value:" + fieldData + fieldData);
270         }
271       }
272     }
273     final String primaryKey1 = primaryKey;
274     final Object[] summaryRowData1 = summaryRowData;
275
276     return new FTSData()
277     {
278
279       @Override
280       public Object[] getSummaryData()
281       {
282         return summaryRowData1;
283       }
284
285       @Override
286       public Object getPrimaryKey()
287       {
288         return primaryKey1;
289       }
290
291       /**
292        * Returns a string representation of this object;
293        */
294       @Override
295       public String toString()
296       {
297         StringBuilder summaryFieldValues = new StringBuilder();
298         for (Object summaryField : summaryRowData1)
299         {
300           summaryFieldValues.append(
301                   summaryField == null ? " " : summaryField.toString())
302                   .append("\t");
303         }
304         return summaryFieldValues.toString();
305       }
306
307       /**
308        * Returns hash code value for this object
309        */
310       @Override
311       public int hashCode()
312       {
313         return Objects.hash(primaryKey1, this.toString());
314       }
315
316       @Override
317       public boolean equals(Object that)
318       {
319         return this.toString().equals(that.toString());
320       }
321     };
322   }
323
324   // private static FTSData getFTSData(Map<String, Object> doc,
325   // FTSRestRequest tdbRestRequest)
326   // {
327   // String primaryKey = null;
328   //
329   // Object[] summaryRowData;
330   //
331   // Collection<FTSDataColumnI> displayFields =
332   // tdbRestRequest.getWantedFields();
333   // int colCounter = 0;
334   // summaryRowData = new Object[displayFields.size() + 1];
335   //
336   // return null;
337   // }
338
339   private String parseJsonExceptionString(String jsonErrorString)
340   {
341     // TODO Auto-generated method stub
342     return null;
343   }
344
345   @Override
346   public String getColumnDataConfigFileName()
347   {
348     return "/fts/tdbeacons_data_columns.txt";
349   }
350
351   public static FTSRestClientI getInstance()
352   {
353     if (instance == null)
354     {
355       instance = new TDBeaconsFTSRestClient();
356     }
357     return instance;
358   }
359
360   private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
361
362   public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
363   {
364     if (allDefaultDisplayedStructureDataColumns == null
365             || allDefaultDisplayedStructureDataColumns.isEmpty())
366     {
367       allDefaultDisplayedStructureDataColumns = new ArrayList<>();
368       allDefaultDisplayedStructureDataColumns
369               .addAll(super.getAllDefaultDisplayedFTSDataColumns());
370     }
371     return allDefaultDisplayedStructureDataColumns;
372   }
373
374   @Override
375   public String[] getPreferencesColumnsFor(PreferenceSource source)
376   {
377     String[] columnNames = null;
378     switch (source)
379     {
380     case SEARCH_SUMMARY:
381       columnNames = new String[] { "", "Display", "Group" };
382       break;
383     case STRUCTURE_CHOOSER:
384       columnNames = new String[] { "", "Display", "Group" };
385       break;
386     case PREFERENCES:
387       columnNames = new String[] { "3DB Beacons Field", "Show in search summary",
388           "Show in structure summary" };
389       break;
390     default:
391       break;
392     }
393     return columnNames;
394   }
395 }