2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.ws.dbsources;
23 import jalview.util.MessageManager;
24 import jalview.ws.uimodel.PDBRestRequest;
25 import jalview.ws.uimodel.PDBRestResponse;
26 import jalview.ws.uimodel.PDBRestResponse.PDBResponseSummary;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Iterator;
31 import java.util.List;
33 import javax.ws.rs.core.MediaType;
35 import org.json.simple.JSONArray;
36 import org.json.simple.JSONObject;
37 import org.json.simple.parser.JSONParser;
38 import org.json.simple.parser.ParseException;
40 import com.sun.jersey.api.client.Client;
41 import com.sun.jersey.api.client.ClientResponse;
42 import com.sun.jersey.api.client.WebResource;
43 import com.sun.jersey.api.client.config.ClientConfig;
44 import com.sun.jersey.api.client.config.DefaultClientConfig;
47 * A rest client for querying the Search endpoing of the PDB REST API
52 public class PDBRestClient
54 public static final String PDB_SEARCH_ENDPOINT = "http://www.ebi.ac.uk/pdbe/search/pdb/select?";
56 private static int DEFAULT_RESPONSE_SIZE = 200;
59 * Takes a PDBRestRequest object and returns a response upon execution
61 * @param pdbRestRequest
62 * the PDBRestRequest instance to be processed
63 * @return the pdbResponse object for the given request
66 public PDBRestResponse executeRequest(PDBRestRequest pdbRestRequest)
71 ClientConfig clientConfig = new DefaultClientConfig();
72 Client client = Client.create(clientConfig);
74 String wantedFields = getPDBDocFieldsAsCommaDelimitedString(pdbRestRequest
76 int responseSize = (pdbRestRequest.getResponseSize() == 0) ? DEFAULT_RESPONSE_SIZE
77 : pdbRestRequest.getResponseSize();
78 String sortParam = null;
79 if (pdbRestRequest.getFieldToSortBy() == null
80 || pdbRestRequest.getFieldToSortBy().trim().isEmpty())
86 if (pdbRestRequest.getFieldToSortBy()
87 .equalsIgnoreCase("Resolution"))
89 sortParam = pdbRestRequest.getFieldToSortBy()
90 + (pdbRestRequest.isAscending() ? " asc" : " desc");
94 sortParam = pdbRestRequest.getFieldToSortBy()
95 + (pdbRestRequest.isAscending() ? " desc" : " asc");
99 String facetPivot = (pdbRestRequest.getFacetPivot() == null || pdbRestRequest
100 .getFacetPivot().isEmpty()) ? "" : pdbRestRequest
102 String facetPivotMinCount = String.valueOf(pdbRestRequest
103 .getFacetPivotMinCount());
105 // Build request parameters for the REST Request
106 WebResource webResource = null;
107 if (pdbRestRequest.isFacet())
109 webResource = client.resource(PDB_SEARCH_ENDPOINT)
110 .queryParam("wt", "json").queryParam("fl", wantedFields)
111 .queryParam("rows", String.valueOf(responseSize))
112 .queryParam("q", pdbRestRequest.getQuery())
113 .queryParam("sort", sortParam).queryParam("facet", "true")
114 .queryParam("facet.pivot", facetPivot)
115 .queryParam("facet.pivot.mincount", facetPivotMinCount);
119 webResource = client.resource(PDB_SEARCH_ENDPOINT)
120 .queryParam("wt", "json").queryParam("fl", wantedFields)
121 .queryParam("rows", String.valueOf(responseSize))
122 .queryParam("q", pdbRestRequest.getQuery())
123 .queryParam("sort", sortParam);
125 // Execute the REST request
126 ClientResponse clientResponse = webResource.accept(
127 MediaType.APPLICATION_JSON).get(ClientResponse.class);
129 // Get the JSON string from the response object
130 String responseString = clientResponse.getEntity(String.class);
131 // System.out.println("query >>>>>>> " + pdbRestRequest.toString());
133 // Check the response status and report exception if one occurs
134 if (clientResponse.getStatus() != 200)
136 String errorMessage = "";
137 if (clientResponse.getStatus() == 400)
139 errorMessage = parseJsonExceptionString(responseString);
140 throw new Exception(errorMessage);
144 errorMessage = getMessageByHTTPStatusCode(clientResponse
146 throw new Exception(errorMessage);
150 // Make redundant objects eligible for garbage collection to conserve
152 clientResponse = null;
155 // Process the response and return the result to the caller.
156 return parsePDBJsonResponse(responseString, pdbRestRequest);
157 } catch (Exception e)
159 String exceptionMsg = e.getMessage();
160 if (exceptionMsg.contains("SocketException"))
162 // No internet connection
165 .getString("exception.unable_to_detect_internet_connection"));
167 else if (exceptionMsg.contains("UnknownHostException"))
169 // The server 'www.ebi.ac.uk' is unreachable
172 .getString("exception.pdb_server_unreachable"));
181 public String getMessageByHTTPStatusCode(int code)
187 message = MessageManager
188 .getString("exception.pdb_rest_service_no_longer_available");
192 message = MessageManager.getString("exception.resource_not_be_found");
202 message = MessageManager.getString("exception.pdb_server_error");
212 * Process error response from PDB server if/when one occurs.
214 * @param jsonResponse
215 * the JSON string containing error message from the server
216 * @return the processed error message from the JSON string
218 public static String parseJsonExceptionString(String jsonErrorResponse)
220 StringBuilder errorMessage = new StringBuilder(
221 "\n============= PDB Rest Client RunTime error =============\n");
225 JSONParser jsonParser = new JSONParser();
226 JSONObject jsonObj = (JSONObject) jsonParser.parse(jsonErrorResponse);
227 JSONObject errorResponse = (JSONObject) jsonObj.get("error");
229 JSONObject responseHeader = (JSONObject) jsonObj
230 .get("responseHeader");
231 JSONObject paramsObj = (JSONObject) responseHeader.get("params");
232 String status = responseHeader.get("status").toString();
233 String message = errorResponse.get("msg").toString();
234 String query = paramsObj.get("q").toString();
235 String fl = paramsObj.get("fl").toString();
237 errorMessage.append("Status: ").append(status).append("\n");
238 errorMessage.append("Message: ").append(message).append("\n");
239 errorMessage.append("query: ").append(query).append("\n");
240 errorMessage.append("fl: ").append(fl).append("\n");
242 } catch (ParseException e)
246 return errorMessage.toString();
250 * Parses the JSON response string from PDB REST API. The response is dynamic
251 * hence, only fields specifically requested for in the 'wantedFields'
252 * parameter is fetched/processed
254 * @param pdbJsonResponseString
255 * the JSON string to be parsed
256 * @param pdbRestRequest
257 * the request object which contains parameters used to process the
261 @SuppressWarnings("unchecked")
262 public static PDBRestResponse parsePDBJsonResponse(
263 String pdbJsonResponseString, PDBRestRequest pdbRestRequest)
265 PDBRestResponse searchResult = new PDBRestResponse();
266 List<PDBResponseSummary> result = null;
269 JSONParser jsonParser = new JSONParser();
270 JSONObject jsonObj = (JSONObject) jsonParser
271 .parse(pdbJsonResponseString);
273 JSONObject pdbResponse = (JSONObject) jsonObj.get("response");
274 String queryTime = ((JSONObject) jsonObj.get("responseHeader")).get(
276 int numFound = Integer
277 .valueOf(pdbResponse.get("numFound").toString());
280 result = new ArrayList<PDBResponseSummary>();
281 JSONArray docs = (JSONArray) pdbResponse.get("docs");
282 for (Iterator<JSONObject> docIter = docs.iterator(); docIter
285 JSONObject doc = docIter.next();
286 result.add(searchResult.new PDBResponseSummary(doc,
289 searchResult.setNumberOfItemsFound(numFound);
290 searchResult.setResponseTime(queryTime);
291 searchResult.setSearchSummary(result);
293 } catch (ParseException e)
301 * Takes a collection of PDBDocField and converts its 'code' Field values into
302 * a comma delimited string.
304 * @param pdbDocfields
305 * the collection of PDBDocField to process
306 * @return the comma delimited string from the pdbDocFields collection
308 public static String getPDBDocFieldsAsCommaDelimitedString(
309 Collection<PDBDocField> pdbDocfields)
312 if (pdbDocfields != null && !pdbDocfields.isEmpty())
314 StringBuilder returnedFields = new StringBuilder();
315 for (PDBDocField field : pdbDocfields)
317 returnedFields.append(",").append(field.getCode());
319 returnedFields.deleteCharAt(0);
320 result = returnedFields.toString();
326 * Determines the column index for 'PDB Id' Fields in the dynamic summary
327 * table. The PDB Id serves as a unique identifier for a given row in the
330 * @param wantedFields
331 * the available table columns in no particular order
332 * @return the pdb id field column index
334 public static int getPDBIdColumIndex(
335 Collection<PDBDocField> wantedFields, boolean hasRefSeq)
338 // If a reference sequence is attached then start counting from 1 else
340 int pdbFieldIndexCounter = hasRefSeq ? 1 : 0;
342 for (PDBDocField field : wantedFields)
344 if (field.equals(PDBDocField.PDB_ID))
346 break; // Once PDB Id index is determined exit iteration
348 ++pdbFieldIndexCounter;
350 return pdbFieldIndexCounter;
353 public static PDBDocField getPDBDocFieldByCode(String fieldCode)
356 for (PDBDocField curPDBDocField : PDBDocField.values())
358 if (curPDBDocField.getCode().equalsIgnoreCase(fieldCode))
360 return curPDBDocField;
363 throw new Exception("PDB doc Field not found!");
367 * This enum represents the fields available in the PDB JSON response
370 public enum PDBDocField
372 PDB_ID("PDB Id", "pdb_id", Group.CROSS_REFS), TITLE(
374 "title", Group.MISCELLENOUS),
375 MOLECULE_NAME("Molecule",
377 Group.NAMES_AND_TAXONOMY), MOLECULE_TYPE(
378 "Molecule Type", "molecule_type", Group.NAMES_AND_TAXONOMY), MOLECULE_SEQUENCE(
379 "Sequence", "molecule_sequence", Group.MISCELLENOUS), PFAM_ACCESSION(
380 "PFAM Accession", "pfam_accession",
381 Group.CROSS_REFS), PFAM_NAME(
382 "PFAM Name", "pfam_name", Group.NAMES_AND_TAXONOMY), INTERPRO_NAME(
383 "InterPro Name", "interpro_name", Group.NAMES_AND_TAXONOMY), INTERPRO_ACCESSION(
384 "InterPro Accession", "interpro_accession",
385 Group.CROSS_REFS), UNIPROT_ID("UniProt Id",
386 "uniprot_id", Group.CROSS_REFS), UNIPROT_ACCESSION(
387 "UniProt Accession", "uniprot_accession",
391 "UniProt Coverage", "uniprot_coverage", Group.MISCELLENOUS), UNIPROT_FEATURES(
392 "Uniprot Features", "uniprot_features", Group.MISCELLENOUS), R_FACTOR(
394 "r_factor", Group.QUALITY_MEASURES), RESOLUTION("Resolution",
395 "resolution", Group.QUALITY_MEASURES), DATA_QUALITY(
396 "Data Quality", "data_quality", Group.QUALITY_MEASURES), OVERALL_QUALITY(
397 "Overall Quality", "overall_quality", Group.QUALITY_MEASURES), POLYMER_COUNT(
398 "Number of Polymers", "number_of_polymers", Group.MISCELLENOUS), PROTEIN_CHAIN_COUNT(
399 "Number of Protein Chains", "number_of_protein_chains",
400 Group.MISCELLENOUS), BOUND_MOLECULE_COUNT(
401 "Number of Bound Molecule", "number_of_bound_molecules",
402 Group.MISCELLENOUS), POLYMER_RESIDUE_COUNT(
403 "Number of Polymer Residue", "number_of_polymer_residues",
404 Group.MISCELLENOUS), GENUS("GENUS", "genus",
405 Group.NAMES_AND_TAXONOMY), GENE_NAME("Gene Name", "gene_name",
406 Group.NAMES_AND_TAXONOMY), EXPERIMENTAL_METHOD(
407 "Experimental Method", "experimental_method",
408 Group.PROCEDURE_AND_SOFTWARE), GO_ID("GO Id", "go_id",
409 Group.CROSS_REFS), ASSEMBLY_ID("Assembly Id",
410 "assembly_id", Group.CROSS_REFS), ASSEMBLY_FORM(
411 "Assembly Form", "assembly_form", Group.MISCELLENOUS), ASSEMBLY_TYPE(
412 "Assembly Type", "assembly_type", Group.MISCELLENOUS), SPACE_GROUP(
413 "Space Group", "spacegroup", Group.MISCELLENOUS), CATH_CODE(
414 "Cath Code", "cath_code", Group.CROSS_REFS), TAX_ID(
415 "Tax Id", "tax_id", Group.CROSS_REFS), TAX_QUERY(
416 "Tax Query", "tax_query", Group.CROSS_REFS), INTERACTING_ENTITY_ID(
417 "Interacting Entity Id", "interacting_entity_id",
418 Group.CROSS_REFS), INTERACTING_MOLECULES(
419 "Interacting Molecules", "interacting_molecules",
420 Group.MISCELLENOUS), PUBMED_ID("Pubmed Id", "pubmed_id",
421 Group.CROSS_REFS), STATUS("Status", "status",
422 Group.MISCELLENOUS), MODEL_QUALITY("Model Quality",
423 "model_quality", Group.QUALITY_MEASURES), PIVOT_RESOLUTION(
424 "Pivot Resolution", "pivot_resolution", Group.QUALITY_MEASURES), DATA_REDUCTION_SOFTWARE(
425 "Data reduction software", "data_reduction_software",
426 Group.PROCEDURE_AND_SOFTWARE), MAX_OBSERVED_RES(
427 "Max observed residues",
428 "max_observed_residues", Group.MISCELLENOUS), ORG_SCI_NAME(
429 "Organism scientific name", "organism_scientific_name",
430 Group.NAMES_AND_TAXONOMY), SUPER_KINGDOM("Super kingdom",
431 "superkingdom", Group.NAMES_AND_TAXONOMY), RANK("Rank", "rank",
432 Group.NAMES_AND_TAXONOMY), CRYSTALLISATION_PH(
433 "Crystallisation Ph",
434 "crystallisation_ph", Group.MISCELLENOUS), BIOLOGICAL_FUNCTION(
435 "Biological Function", "biological_function",
436 Group.MISCELLENOUS), BIOLOGICAL_PROCESS("Biological Process",
437 "biological_process", Group.MISCELLENOUS), BIOLOGICAL_CELL_COMPONENT(
438 "Biological Cell Component", "biological_cell_component",
439 Group.MISCELLENOUS), COMPOUND_NAME("Compound Name",
440 "compound_name", Group.NAMES_AND_TAXONOMY), COMPOUND_ID(
441 "Compound Id", "compound_id", Group.CROSS_REFS), COMPOUND_WEIGHT(
442 "Compound Weight", "compound_weight", Group.MISCELLENOUS), COMPOUND_SYSTEMATIC_NAME(
443 "Compound Systematic Name", "compound_systematic_name",
444 Group.NAMES_AND_TAXONOMY), INTERACTING_LIG(
445 "Interacting Ligands",
446 "interacting_ligands", Group.MISCELLENOUS), JOURNAL("Journal",
447 "journal", Group.MISCELLENOUS), ALL_AUTHORS("All Authors",
448 "all_authors", Group.MISCELLENOUS), EXPERIMENTAL_DATA_AVAILABLE(
449 "Experiment Data Available", "experiment_data_available",
450 Group.MISCELLENOUS), DIFFRACTION_PROTOCOL(
451 "Diffraction Protocol", "diffraction_protocol",
452 Group.PROCEDURE_AND_SOFTWARE), REFINEMENT_SOFTWARE(
453 "Refinement Software", "refinement_software",
454 Group.PROCEDURE_AND_SOFTWARE), STRUCTURE_DETERMINATION_METHOD(
455 "Structure Determination Method",
456 "structure_determination_method", Group.PROCEDURE_AND_SOFTWARE), SYNCHROTON_SITE(
457 "Synchrotron Site", "synchrotron_site", Group.MISCELLENOUS), SAMPLE_PREP_METHOD(
458 "Sample Preparation Method", "sample_preparation_method",
459 Group.PROCEDURE_AND_SOFTWARE), ENTRY_AUTHORS("Entry Authors",
460 "entry_authors", Group.MISCELLENOUS), CITATION_TITLE(
461 "Citation Title", "citation_title", Group.MISCELLENOUS), STRUCTURE_SOLUTION_SOFTWARE(
462 "Structure Solution Software", "structure_solution_software",
463 Group.PROCEDURE_AND_SOFTWARE), ENTRY_ENTITY("Entry Entity",
464 "entry_entity", Group.MISCELLENOUS), R_FREE("R Free", "r_free",
465 Group.QUALITY_MEASURES), NO_OF_POLYMER_ENTITIES(
466 "Number of Polymer Entities", "number_of_polymer_entities",
467 Group.MISCELLENOUS), NO_OF_BOUND_ENTITIES(
468 "Number of Bound Entities", "number_of_bound_entities",
469 Group.MISCELLENOUS), CRYSTALLISATION_RESERVOIR(
470 "Crystallisation Reservoir", "crystallisation_reservoir",
471 Group.MISCELLENOUS), DATA_SCALING_SW("Data Scalling Software",
472 "data_scaling_software", Group.PROCEDURE_AND_SOFTWARE), DETECTOR(
473 "Detector", "detector", Group.MISCELLENOUS), DETECTOR_TYPE(
474 "Detector Type", "detector_type", Group.MISCELLENOUS), MODIFIED_RESIDUE_FLAG(
475 "Modified Residue Flag", "modified_residue_flag",
476 Group.MISCELLENOUS), NUMBER_OF_COPIES("Number of Copies",
477 "number_of_copies", Group.MISCELLENOUS), STRUCT_ASYM_ID(
478 "Struc Asym Id", "struct_asym_id",
479 Group.CROSS_REFS), HOMOLOGUS_PDB_ENTITY_ID(
480 "Homologus PDB Entity Id", "homologus_pdb_entity_id",
481 Group.CROSS_REFS), MOLECULE_SYNONYM(
483 "molecule_synonym", Group.MISCELLENOUS), DEPOSITION_SITE(
484 "Deposition Site", "deposition_site", Group.MISCELLENOUS), SYNCHROTRON_BEAMLINE(
485 "Synchrotron Beamline", "synchrotron_beamline",
486 Group.MISCELLENOUS), ENTITY_ID("Entity Id", "entity_id",
487 Group.CROSS_REFS), BEAM_SOURCE_NAME(
490 Group.NAMES_AND_TAXONOMY), PROCESSING_SITE(
491 "Processing Site", "processing_site", Group.MISCELLENOUS), ENTITY_WEIGHT(
492 "Entity Weight", "entity_weight", Group.MISCELLENOUS), VERSION(
493 "Version", "_version_", Group.MISCELLENOUS), ALL("ALL", "text",
498 DATE_OF("Date Of", 5), NAMES_AND_TAXONOMY("Names & Taxonomy", 3),
499 MISCELLENOUS("Miscellenous", 6), QUALITY_MEASURES("Quality Measures",
500 1), CROSS_REFS("Cross References", 2),
501 PROCEDURE_AND_SOFTWARE("Procedures & Softwares", 4);
503 Group(String name, int sortOrder)
506 this.sortOrder = sortOrder;
511 private int sortOrder;
513 public String getName()
518 public int getSortOrder()
524 public String toString()
535 PDBDocField(String name, String code, Group group)
542 public String getName()
547 public String getCode()
552 public Group getGroup()
558 public String toString()