JAL-1563 JAL-2091 Added total result count to Uniprot pagination, implemented caching...
[jalview.git] / src / jalview / fts / service / uniprot / UniProtFTSRestClient.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
22 package jalview.fts.service.uniprot;
23
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.util.ArrayList;
33 import java.util.Collection;
34 import java.util.List;
35 import java.util.Objects;
36
37 import javax.ws.rs.core.MediaType;
38
39 import com.sun.jersey.api.client.Client;
40 import com.sun.jersey.api.client.ClientResponse;
41 import com.sun.jersey.api.client.WebResource;
42 import com.sun.jersey.api.client.config.ClientConfig;
43 import com.sun.jersey.api.client.config.DefaultClientConfig;
44
45 public class UniProtFTSRestClient extends FTSRestClient
46 {
47   private static FTSRestClientI instance = null;
48
49   public static final String UNIPROT_SEARCH_ENDPOINT = "http://www.uniprot.org/uniprot/?";
50
51   @Override
52   public FTSRestResponse executeRequest(FTSRestRequest uniportRestRequest)
53           throws Exception
54   {
55     try
56     {
57       ClientConfig clientConfig = new DefaultClientConfig();
58       Client client = Client.create(clientConfig);
59
60       String wantedFields = getDataColumnsFieldsAsCommaDelimitedString(uniportRestRequest
61               .getWantedFields());
62       int responseSize = (uniportRestRequest.getResponseSize() == 0) ? getDefaultResponsePageSize()
63               : uniportRestRequest.getResponseSize();
64
65       int offSet = uniportRestRequest.getOffSet();
66
67       String query = uniportRestRequest.getFieldToSearchBy()
68               .equalsIgnoreCase("Search All") ? uniportRestRequest
69               .getSearchTerm() : uniportRestRequest.getFieldToSearchBy()
70               + ":" + uniportRestRequest.getSearchTerm();
71
72       // + (uniportRestRequest.isAllowUnpublishedEntries() ? ""
73       // : " AND status:REL");
74       // System.out.println(">>>>> Query : " + query);
75       // System.out.println(">>>>> Columns : " + wantedFields);
76       // System.out.println(">>>>> Response size: " + responseSize
77       // + " offset : "
78       // + offSet);
79       WebResource webResource = null;
80       webResource = client.resource(UNIPROT_SEARCH_ENDPOINT)
81               .queryParam("format", "tab")
82               .queryParam("columns", wantedFields)
83               .queryParam("limit", String.valueOf(responseSize))
84               .queryParam("offset", String.valueOf(offSet))
85               .queryParam("sort", "score").queryParam("query", query);
86       // Execute the REST request
87       ClientResponse clientResponse = webResource.accept(
88               MediaType.TEXT_PLAIN).get(ClientResponse.class);
89       String uniProtTabDelimittedResponseString = clientResponse
90               .getEntity(String.class);
91       // Make redundant objects eligible for garbage collection to conserve
92       // memory
93       // System.out.println(">>>>> response : "
94       // + uniProtTabDelimittedResponseString);
95       if (clientResponse.getStatus() != 200)
96       {
97         String errorMessage = getMessageByHTTPStatusCode(
98                 clientResponse.getStatus(), "Uniprot");
99         throw new Exception(errorMessage);
100
101       }
102       int xTotalResults = Integer.valueOf(clientResponse.getHeaders()
103               .get("X-Total-Results").get(0));
104       clientResponse = null;
105       client = null;
106       return parseUniprotResponse(uniProtTabDelimittedResponseString,
107               uniportRestRequest, xTotalResults);
108     } catch (Exception e)
109     {
110       String exceptionMsg = e.getMessage();
111       if (exceptionMsg.contains("SocketException"))
112       {
113         // No internet connection
114         throw new Exception(
115                 MessageManager
116                         .getString("exception.unable_to_detect_internet_connection"));
117       }
118       else if (exceptionMsg.contains("UnknownHostException"))
119       {
120         // The server 'http://www.uniprot.org' is unreachable
121         throw new Exception(MessageManager.formatMessage(
122                 "exception.fts_server_unreachable", "Uniprot"));
123       }
124       else
125       {
126         throw e;
127       }
128     }
129   }
130
131
132   public FTSRestResponse parseUniprotResponse(
133           String uniProtTabDelimittedResponseString,
134           FTSRestRequest uniprotRestRequest, int xTotalResults)
135   {
136     FTSRestResponse searchResult = new FTSRestResponse();
137     List<FTSData> result = null;
138     if (uniProtTabDelimittedResponseString == null
139             || uniProtTabDelimittedResponseString.trim().isEmpty())
140     {
141       searchResult.setNumberOfItemsFound(0);
142       return searchResult;
143     }
144     String[] foundDataRow = uniProtTabDelimittedResponseString.split("\n");
145     if (foundDataRow != null && foundDataRow.length > 0)
146     {
147       result = new ArrayList<FTSData>();
148       String titleRow = getDataColumnsFieldsAsTabDelimitedString(uniprotRestRequest
149               .getWantedFields());
150       // System.out.println(">>>>Title row : " + titleRow);
151       for (String dataRow : foundDataRow)
152       {
153         if (dataRow.equalsIgnoreCase(titleRow))
154         {
155           // System.out.println(">>>>>>>>>> matched!!!");
156           continue;
157         }
158         // System.out.println(dataRow);
159         result.add(getFTSData(dataRow, uniprotRestRequest));
160       }
161       searchResult.setNumberOfItemsFound(xTotalResults);
162       searchResult.setSearchSummary(result);
163     }
164     return searchResult;
165   }
166
167   /**
168    * Takes a collection of FTSDataColumnI and converts its 'code' values into a
169    * tab delimited string.
170    * 
171    * @param dataColumnFields
172    *          the collection of FTSDataColumnI to process
173    * @return the generated comma delimited string from the supplied
174    *         FTSDataColumnI collection
175    */
176   private String getDataColumnsFieldsAsTabDelimitedString(
177           Collection<FTSDataColumnI> dataColumnFields)
178   {
179     String result = "";
180     if (dataColumnFields != null && !dataColumnFields.isEmpty())
181     {
182       StringBuilder returnedFields = new StringBuilder();
183       for (FTSDataColumnI field : dataColumnFields)
184       {
185         if (field.getName().equalsIgnoreCase("Uniprot Id"))
186         {
187           returnedFields.append("\t").append("Entry");
188         }
189         else
190         {
191           returnedFields.append("\t").append(field.getName());
192         }
193       }
194       returnedFields.deleteCharAt(0);
195       result = returnedFields.toString();
196     }
197     return result;
198   }
199
200   public static FTSData getFTSData(String tabDelimittedDataStr,
201           FTSRestRequest request)
202   {
203     String primaryKey = null;
204
205     Object[] summaryRowData;
206
207     Collection<FTSDataColumnI> diplayFields = request.getWantedFields();
208     int colCounter = 0;
209     summaryRowData = new Object[diplayFields.size()];
210     String[] columns = tabDelimittedDataStr.split("\t");
211     for (FTSDataColumnI field : diplayFields)
212     {
213       try
214       {
215         String fieldData = columns[colCounter];
216         if (field.isPrimaryKeyColumn())
217         {
218           primaryKey = fieldData;
219           summaryRowData[colCounter++] = primaryKey;
220         }
221         else if (fieldData == null || fieldData.isEmpty())
222         {
223           summaryRowData[colCounter++] = null;
224         }
225         else
226         {
227           try
228           {
229             summaryRowData[colCounter++] = (field.getDataColumnClass() == Integer.class) ? Integer
230                     .valueOf(fieldData)
231                     : (field.getDataColumnClass() == Double.class) ? Double
232                             .valueOf(fieldData) : fieldData;
233           } catch (Exception e)
234           {
235             e.printStackTrace();
236               System.out.println("offending value:" + fieldData);
237           }
238         }
239       } catch (Exception e)
240       {
241         // e.printStackTrace();
242       }
243     }
244
245     final String primaryKey1 = primaryKey;
246
247     final Object[] summaryRowData1 = summaryRowData;
248     return new FTSData()
249     {
250       @Override
251       public Object[] getSummaryData()
252       {
253         return summaryRowData1;
254       }
255
256       @Override
257       public Object getPrimaryKey()
258       {
259         return primaryKey1;
260       }
261
262       /**
263        * Returns a string representation of this object;
264        */
265       @Override
266       public String toString()
267       {
268         StringBuilder summaryFieldValues = new StringBuilder();
269         for (Object summaryField : summaryRowData1)
270         {
271           summaryFieldValues.append(
272                   summaryField == null ? " " : summaryField.toString())
273                   .append("\t");
274         }
275         return summaryFieldValues.toString();
276       }
277
278       /**
279        * Returns hash code value for this object
280        */
281       @Override
282       public int hashCode()
283       {
284         return Objects.hash(primaryKey1, this.toString());
285       }
286
287       @Override
288       public boolean equals(Object that)
289       {
290         return this.toString().equals(that.toString());
291       }
292     };
293   }
294
295
296   public static FTSRestClientI getInstance()
297   {
298     if (instance == null)
299     {
300       instance = new UniProtFTSRestClient();
301     }
302     return instance;
303   }
304
305   @Override
306   public String getColumnDataConfigFileName()
307   {
308     return "/fts/uniprot_data_columns.txt";
309   }
310
311 }