Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.fts.service.pdb

File PDBFTSRestClient.java

 

Coverage histogram

../../../../img/srcFileCovDistChart4.png
45% of files have more coverage

Code metrics

52
135
15
1
509
352
50
0.37
9
15
3.33

Classes

Class Line # Actions
PDBFTSRestClient 67 135 50 126
0.3762376337.6%
 

Contributing tests

This file is covered by 4 tests. .

Source view

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.service.pdb;
22   
23    import jalview.datamodel.SequenceI;
24    import jalview.fts.api.FTSData;
25    import jalview.fts.api.FTSDataColumnI;
26    import jalview.fts.api.FTSRestClientI;
27    import jalview.fts.core.FTSRestClient;
28    import jalview.fts.core.FTSRestRequest;
29    import jalview.fts.core.FTSRestResponse;
30    import jalview.util.MessageManager;
31   
32    import java.net.URI;
33    import java.util.ArrayList;
34    import java.util.Collection;
35    import java.util.Iterator;
36    import java.util.List;
37    import java.util.Objects;
38   
39    import javax.ws.rs.core.MediaType;
40   
41    import org.json.simple.JSONArray;
42    import org.json.simple.JSONObject;
43    import org.json.simple.parser.JSONParser;
44    import org.json.simple.parser.ParseException;
45   
46    //import jalview.javascript.web.Client;
47    //import jalview.javascript.web.ClientResponse;
48    //import jalview.javascript.web.WebResource;
49   
50    import com.sun.jersey.api.client.Client;
51    import com.sun.jersey.api.client.ClientResponse;
52    import com.sun.jersey.api.client.WebResource;
53   
54    import com.sun.jersey.api.client.config.ClientConfig;
55    import com.sun.jersey.api.client.config.DefaultClientConfig;
56   
57    /**
58    * A rest client for querying the Search endpoint of the PDB API
59    *
60    * BH 2018: just a tiny tweak here - for SwingJS, we coerce the classes to be
61    * from jalview.javascript.web instead of com.sun.jersey.api.client
62    *
63    *
64    * @author tcnofoegbu
65    *
66    */
 
67    public class PDBFTSRestClient extends FTSRestClient
68    {
69   
70    private static FTSRestClientI instance = null;
71   
72    public static final String PDB_SEARCH_ENDPOINT = "https://www.ebi.ac.uk/pdbe/search/pdb/select?";
73   
 
74  1 toggle protected PDBFTSRestClient()
75    {
76    }
77   
78    /**
79    * Takes a PDBRestRequest object and returns a response upon execution
80    *
81    * @param pdbRestRequest
82    * the PDBRestRequest instance to be processed
83    * @return the pdbResponse object for the given request
84    * @throws Exception
85    */
 
86  1 toggle @SuppressWarnings({ "unused", "unchecked" })
87    @Override
88    public FTSRestResponse executeRequest(FTSRestRequest pdbRestRequest)
89    throws Exception
90    {
91  1 try
92    {
93  1 Client client;
94  1 WebResource webResource;
95   
96  1 String wantedFields = getDataColumnsFieldsAsCommaDelimitedString(
97    pdbRestRequest.getWantedFields());
98  1 int responseSize = (pdbRestRequest.getResponseSize() == 0)
99    ? getDefaultResponsePageSize()
100    : pdbRestRequest.getResponseSize();
101  1 int offSet = pdbRestRequest.getOffSet();
102  1 String sortParam = null;
103  1 if (pdbRestRequest.getFieldToSortBy() == null
104    || pdbRestRequest.getFieldToSortBy().trim().isEmpty())
105    {
106  0 sortParam = "";
107    }
108    else
109    {
110  1 if (pdbRestRequest.getFieldToSortBy()
111    .equalsIgnoreCase("Resolution"))
112    {
113  0 sortParam = pdbRestRequest.getFieldToSortBy()
114  0 + (pdbRestRequest.isAscending() ? " asc" : " desc");
115    }
116    else
117    {
118  1 sortParam = pdbRestRequest.getFieldToSortBy()
119  1 + (pdbRestRequest.isAscending() ? " desc" : " asc");
120    }
121    }
122   
123  1 String facetPivot = (pdbRestRequest.getFacetPivot() == null
124    || pdbRestRequest.getFacetPivot().isEmpty()) ? ""
125    : pdbRestRequest.getFacetPivot();
126  1 String facetPivotMinCount = String
127    .valueOf(pdbRestRequest.getFacetPivotMinCount());
128   
129  1 String query = pdbRestRequest.getFieldToSearchBy()
130    + pdbRestRequest.getSearchTerm()
131  1 + (pdbRestRequest.isAllowEmptySeq() ? ""
132    : " AND molecule_sequence:['' TO *]")
133  1 + (pdbRestRequest.isAllowUnpublishedEntries() ? ""
134    : " AND status:REL");
135   
136    // Build request parameters for the REST Request
137   
138    // BH 2018 the trick here is to coerce the classes in Javascript to be
139    // different from the ones in Java yet still allow this to be correct for Java
140  1 Class<ClientResponse> clientResponseClass;
141  1 if (/** @j2sNative true || */
142    false)
143    {
144    // JavaScript only -- coerce types to Java types for Java
145  0 client = (Client) (Object) new jalview.javascript.web.Client();
146  0 clientResponseClass = (Class<ClientResponse>) (Object) jalview.javascript.web.ClientResponse.class;
147    }
148    else
149    {
150    // Java only
151  1 client = Client.create(new DefaultClientConfig());
152  1 clientResponseClass = ClientResponse.class;
153    }
154   
155  1 if (pdbRestRequest.isFacet())
156    {
157  0 webResource = client.resource(PDB_SEARCH_ENDPOINT)
158    .queryParam("wt", "json").queryParam("fl", wantedFields)
159    .queryParam("rows", String.valueOf(responseSize))
160    .queryParam("q", query)
161    .queryParam("start", String.valueOf(offSet))
162    .queryParam("sort", sortParam).queryParam("facet", "true")
163    .queryParam("facet.pivot", facetPivot)
164    .queryParam("facet.pivot.mincount", facetPivotMinCount);
165    }
166    else
167    {
168  1 webResource = client.resource(PDB_SEARCH_ENDPOINT)
169    .queryParam("wt", "json").queryParam("fl", wantedFields)
170    .queryParam("rows", String.valueOf(responseSize))
171    .queryParam("start", String.valueOf(offSet))
172    .queryParam("q", query).queryParam("sort", sortParam);
173    }
174   
175  1 URI uri = webResource.getURI();
176   
177    // Execute the REST request
178  1 ClientResponse clientResponse = webResource
179    .accept(MediaType.APPLICATION_JSON).get(clientResponseClass );
180   
181    // Get the JSON string from the response object
182  1 String responseString = clientResponse.getEntity(String.class);
183    // System.out.println("query >>>>>>> " + pdbRestRequest.toString());
184   
185    // Check the response status and report exception if one occurs
186  1 if (clientResponse.getStatus() != 200)
187    {
188  1 String errorMessage = "";
189  1 if (clientResponse.getStatus() == 400)
190    {
191  1 errorMessage = parseJsonExceptionString(responseString);
192  1 throw new Exception(errorMessage);
193    }
194    else
195    {
196  0 errorMessage = getMessageByHTTPStatusCode(
197    clientResponse.getStatus(), "PDB");
198  0 throw new Exception(errorMessage);
199    }
200    }
201   
202    // Make redundant objects eligible for garbage collection to conserve
203    // memory
204  0 clientResponse = null;
205  0 client = null;
206   
207    // Process the response and return the result to the caller.
208  0 return parsePDBJsonResponse(responseString, pdbRestRequest);
209    } catch (Exception e)
210    {
211  1 String exceptionMsg = e.getMessage();
212  1 if (exceptionMsg.contains("SocketException"))
213    {
214    // No internet connection
215  0 throw new Exception(MessageManager.getString(
216    "exception.unable_to_detect_internet_connection"));
217    }
218  1 else if (exceptionMsg.contains("UnknownHostException"))
219    {
220    // The server 'www.ebi.ac.uk' is unreachable
221  0 throw new Exception(MessageManager.formatMessage(
222    "exception.fts_server_unreachable", "PDB Solr"));
223    }
224    else
225    {
226  1 throw e;
227    }
228    }
229    }
230   
231    /**
232    * Process error response from PDB server if/when one occurs.
233    *
234    * @param jsonResponse
235    * the JSON string containing error message from the server
236    * @return the processed error message from the JSON string
237    */
 
238  1 toggle public static String parseJsonExceptionString(String jsonErrorResponse)
239    {
240  1 StringBuilder errorMessage = new StringBuilder(
241    "\n============= PDB Rest Client RunTime error =============\n");
242   
243   
244    // {
245    // "responseHeader":{
246    // "status":0,
247    // "QTime":0,
248    // "params":{
249    // "q":"(text:q93xj9_soltu) AND molecule_sequence:['' TO *] AND status:REL",
250    // "fl":"pdb_id,title,experimental_method,resolution",
251    // "start":"0",
252    // "sort":"overall_quality desc",
253    // "rows":"500",
254    // "wt":"json"}},
255    // "response":{"numFound":1,"start":0,"docs":[
256    // {
257    // "experimental_method":["X-ray diffraction"],
258    // "pdb_id":"4zhp",
259    // "resolution":2.46,
260    // "title":"The crystal structure of Potato ferredoxin I with 2Fe-2S cluster"}]
261    // }}
262    //
263  1 try
264    {
265  1 JSONParser jsonParser = new JSONParser();
266  1 JSONObject jsonObj = (JSONObject) jsonParser.parse(jsonErrorResponse);
267  1 JSONObject errorResponse = (JSONObject) jsonObj.get("error");
268   
269  1 JSONObject responseHeader = (JSONObject) jsonObj
270    .get("responseHeader");
271  1 JSONObject paramsObj = (JSONObject) responseHeader.get("params");
272  1 String status = responseHeader.get("status").toString();
273  1 String message = errorResponse.get("msg").toString();
274  1 String query = paramsObj.get("q").toString();
275  1 String fl = paramsObj.get("fl").toString();
276   
277  1 errorMessage.append("Status: ").append(status).append("\n");
278  1 errorMessage.append("Message: ").append(message).append("\n");
279  1 errorMessage.append("query: ").append(query).append("\n");
280  1 errorMessage.append("fl: ").append(fl).append("\n");
281   
282    } catch (ParseException e)
283    {
284  0 e.printStackTrace();
285    }
286  1 return errorMessage.toString();
287    }
288   
289    /**
290    * Parses the JSON response string from PDB REST API. The response is dynamic
291    * hence, only fields specifically requested for in the 'wantedFields'
292    * parameter is fetched/processed
293    *
294    * @param pdbJsonResponseString
295    * the JSON string to be parsed
296    * @param pdbRestRequest
297    * the request object which contains parameters used to process the
298    * JSON string
299    * @return
300    */
 
301  0 toggle @SuppressWarnings("unchecked")
302    public static FTSRestResponse parsePDBJsonResponse(
303    String pdbJsonResponseString, FTSRestRequest pdbRestRequest)
304    {
305  0 FTSRestResponse searchResult = new FTSRestResponse();
306  0 List<FTSData> result = null;
307  0 try
308    {
309  0 JSONParser jsonParser = new JSONParser();
310  0 JSONObject jsonObj = (JSONObject) jsonParser
311    .parse(pdbJsonResponseString);
312   
313  0 JSONObject pdbResponse = (JSONObject) jsonObj.get("response");
314  0 String queryTime = ((JSONObject) jsonObj.get("responseHeader"))
315    .get("QTime").toString();
316  0 int numFound = Integer
317    .valueOf(pdbResponse.get("numFound").toString());
318  0 if (numFound > 0)
319    {
320  0 result = new ArrayList<FTSData>();
321  0 JSONArray docs = (JSONArray) pdbResponse.get("docs");
322  0 for (Iterator<JSONObject> docIter = docs.iterator(); docIter
323    .hasNext();)
324    {
325  0 JSONObject doc = docIter.next();
326  0 result.add(getFTSData(doc, pdbRestRequest));
327    }
328  0 searchResult.setNumberOfItemsFound(numFound);
329  0 searchResult.setResponseTime(queryTime);
330  0 searchResult.setSearchSummary(result);
331    }
332    } catch (ParseException e)
333    {
334  0 e.printStackTrace();
335    }
336  0 return searchResult;
337    }
338   
 
339  0 toggle public static FTSData getFTSData(JSONObject pdbJsonDoc,
340    FTSRestRequest request)
341    {
342   
343  0 String primaryKey = null;
344   
345  0 Object[] summaryRowData;
346   
347  0 SequenceI associatedSequence;
348   
349  0 Collection<FTSDataColumnI> diplayFields = request.getWantedFields();
350  0 SequenceI associatedSeq = request.getAssociatedSequence();
351  0 int colCounter = 0;
352  0 summaryRowData = new Object[(associatedSeq != null)
353    ? diplayFields.size() + 1
354    : diplayFields.size()];
355  0 if (associatedSeq != null)
356    {
357  0 associatedSequence = associatedSeq;
358  0 summaryRowData[0] = associatedSequence;
359  0 colCounter = 1;
360    }
361   
362  0 for (FTSDataColumnI field : diplayFields)
363    {
364  0 String fieldData = (pdbJsonDoc.get(field.getCode()) == null) ? ""
365    : pdbJsonDoc.get(field.getCode()).toString();
366  0 if (field.isPrimaryKeyColumn())
367    {
368  0 primaryKey = fieldData;
369  0 summaryRowData[colCounter++] = primaryKey;
370    }
371  0 else if (fieldData == null || fieldData.isEmpty())
372    {
373  0 summaryRowData[colCounter++] = null;
374    }
375    else
376    {
377  0 try
378    {
379  0 summaryRowData[colCounter++] = (field.getDataType()
380    .getDataTypeClass() == Integer.class)
381    ? Integer.valueOf(fieldData)
382  0 : (field.getDataType()
383    .getDataTypeClass() == Double.class)
384    ? Double.valueOf(fieldData)
385    : sanitiseData(fieldData);
386    } catch (Exception e)
387    {
388  0 e.printStackTrace();
389  0 System.out.println("offending value:" + fieldData);
390    }
391    }
392    }
393   
394  0 final String primaryKey1 = primaryKey;
395   
396  0 final Object[] summaryRowData1 = summaryRowData;
397  0 return new FTSData()
398    {
 
399  0 toggle @Override
400    public Object[] getSummaryData()
401    {
402  0 return summaryRowData1;
403    }
404   
 
405  0 toggle @Override
406    public Object getPrimaryKey()
407    {
408  0 return primaryKey1;
409    }
410   
411    /**
412    * Returns a string representation of this object;
413    */
 
414  0 toggle @Override
415    public String toString()
416    {
417  0 StringBuilder summaryFieldValues = new StringBuilder();
418  0 for (Object summaryField : summaryRowData1)
419    {
420  0 summaryFieldValues.append(
421  0 summaryField == null ? " " : summaryField.toString())
422    .append("\t");
423    }
424  0 return summaryFieldValues.toString();
425    }
426   
427    /**
428    * Returns hash code value for this object
429    */
 
430  0 toggle @Override
431    public int hashCode()
432    {
433  0 return Objects.hash(primaryKey1, this.toString());
434    }
435   
 
436  0 toggle @Override
437    public boolean equals(Object that)
438    {
439  0 return this.toString().equals(that.toString());
440    }
441    };
442    }
443   
 
444  0 toggle private static String sanitiseData(String data)
445    {
446  0 String cleanData = data.replaceAll("\\[\"", "").replaceAll("\\]\"", "")
447    .replaceAll("\\[", "").replaceAll("\\]", "")
448    .replaceAll("\",\"", ", ").replaceAll("\"", "");
449  0 return cleanData;
450    }
451   
 
452  1 toggle @Override
453    public String getColumnDataConfigFileName()
454    {
455  1 return "/fts/pdb_data_columns.txt";
456    }
457   
 
458  19 toggle public static FTSRestClientI getInstance()
459    {
460  19 if (instance == null)
461    {
462  1 instance = new PDBFTSRestClient();
463    }
464  19 return instance;
465    }
466   
467    private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
468   
 
469  1 toggle public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
470    {
471  1 if (allDefaultDisplayedStructureDataColumns == null
472    || allDefaultDisplayedStructureDataColumns.isEmpty())
473    {
474  1 allDefaultDisplayedStructureDataColumns = new ArrayList<FTSDataColumnI>();
475  1 allDefaultDisplayedStructureDataColumns
476    .addAll(super.getAllDefaultDisplayedFTSDataColumns());
477    }
478  1 return allDefaultDisplayedStructureDataColumns;
479    }
480   
 
481  0 toggle public static void main(String[] args) {
482   
483   
484    // check for transpiler fix associated with JSONParser yylex.java use of charAt()
485    // instead of codePointAt()
486   
487  0 String s = "e";
488  0 char c = 'c';
489  0 char f = 'f';
490  0 s += c | f;
491  0 int x = c&f;
492  0 int y = 2 & c;
493  0 int z = c ^ 5;
494  0 String result = s +x + y + z;
495  0 assert (result == "e103982102");
496  0 JSONParser jsonParser = new JSONParser();
497  0 try
498    {
499  0 JSONObject jsonObj = (JSONObject) jsonParser.parse("{\"a\":3}");
500  0 System.out.println(jsonObj);
501    } catch (ParseException e)
502    {
503  0 e.printStackTrace();
504    }
505   
506    }
507   
508   
509    }