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.fts.service.pdb;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Iterator;
27 import java.util.List;
29 import java.util.Objects;
31 import javax.ws.rs.core.MediaType;
33 import org.json.simple.parser.ParseException;
35 import com.sun.jersey.api.client.Client;
36 import com.sun.jersey.api.client.ClientResponse;
37 import com.sun.jersey.api.client.WebResource;
38 import com.sun.jersey.api.client.config.DefaultClientConfig;
40 import jalview.datamodel.SequenceI;
41 import jalview.fts.api.FTSData;
42 import jalview.fts.api.FTSDataColumnI;
43 import jalview.fts.api.FTSRestClientI;
44 import jalview.fts.api.StructureFTSRestClientI;
45 import jalview.fts.core.FTSDataColumnPreferences;
46 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
47 import jalview.fts.core.FTSRestClient;
48 import jalview.fts.core.FTSRestRequest;
49 import jalview.fts.core.FTSRestResponse;
50 import jalview.fts.service.alphafold.AlphafoldRestClient;
51 import jalview.util.JSONUtils;
52 import jalview.util.MessageManager;
53 import jalview.util.Platform;
56 * A rest client for querying the Search endpoint of the PDB API
60 public class PDBFTSRestClient extends FTSRestClient implements StructureFTSRestClientI
63 private static FTSRestClientI instance = null;
65 public static final String PDB_SEARCH_ENDPOINT = "https://www.ebi.ac.uk/pdbe/search/pdb/select?";
67 protected PDBFTSRestClient()
72 * Takes a PDBRestRequest object and returns a response upon execution
74 * @param pdbRestRequest
75 * the PDBRestRequest instance to be processed
76 * @return the pdbResponse object for the given request
79 @SuppressWarnings({ "unused", "unchecked" })
81 public FTSRestResponse executeRequest(FTSRestRequest pdbRestRequest)
86 String wantedFields = getDataColumnsFieldsAsCommaDelimitedString(
87 pdbRestRequest.getWantedFields());
88 int responseSize = (pdbRestRequest.getResponseSize() == 0)
89 ? getDefaultResponsePageSize()
90 : pdbRestRequest.getResponseSize();
91 int offSet = pdbRestRequest.getOffSet();
92 String sortParam = null;
93 if (pdbRestRequest.getFieldToSortBy() == null
94 || pdbRestRequest.getFieldToSortBy().trim().isEmpty())
100 if (pdbRestRequest.getFieldToSortBy()
101 .equalsIgnoreCase("Resolution"))
103 sortParam = pdbRestRequest.getFieldToSortBy()
104 + (pdbRestRequest.isAscending() ? " asc" : " desc");
108 sortParam = pdbRestRequest.getFieldToSortBy()
109 + (pdbRestRequest.isAscending() ? " desc" : " asc");
113 String facetPivot = (pdbRestRequest.getFacetPivot() == null
114 || pdbRestRequest.getFacetPivot().isEmpty()) ? ""
115 : pdbRestRequest.getFacetPivot();
116 String facetPivotMinCount = String
117 .valueOf(pdbRestRequest.getFacetPivotMinCount());
119 String query = pdbRestRequest.getFieldToSearchBy()
120 + pdbRestRequest.getSearchTerm()
121 + (pdbRestRequest.isAllowEmptySeq() ? ""
122 : " AND molecule_sequence:['' TO *]")
123 + (pdbRestRequest.isAllowUnpublishedEntries() ? ""
124 : " AND status:REL");
126 // Build request parameters for the REST Request
128 // BH 2018 the trick here is to coerce the classes in Javascript to be
129 // different from the ones in Java yet still allow this to be correct for Java
131 Class<ClientResponse> clientResponseClass;
134 // JavaScript only -- coerce types to Java types for Java
135 client = (Client) (Object) new jalview.javascript.web.Client();
136 clientResponseClass = (Class<ClientResponse>) (Object) jalview.javascript.web.ClientResponse.class;
145 client = Client.create(new DefaultClientConfig());
146 clientResponseClass = ClientResponse.class;
149 WebResource webResource;
150 if (pdbRestRequest.isFacet())
152 webResource = client.resource(PDB_SEARCH_ENDPOINT)
153 .queryParam("wt", "json").queryParam("fl", wantedFields)
154 .queryParam("rows", String.valueOf(responseSize))
155 .queryParam("q", query)
156 .queryParam("start", String.valueOf(offSet))
157 .queryParam("sort", sortParam).queryParam("facet", "true")
158 .queryParam("facet.pivot", facetPivot)
159 .queryParam("facet.pivot.mincount", facetPivotMinCount);
163 webResource = client.resource(PDB_SEARCH_ENDPOINT)
164 .queryParam("wt", "json").queryParam("fl", wantedFields)
165 .queryParam("rows", String.valueOf(responseSize))
166 .queryParam("start", String.valueOf(offSet))
167 .queryParam("q", query).queryParam("sort", sortParam);
170 URI uri = webResource.getURI();
172 System.out.println(uri);
173 ClientResponse clientResponse =null;
174 int responseStatus = -1;
175 // Get the JSON string from the response object or directly from the
176 // client (JavaScript)
177 Map<String, Object> jsonObj = null;
178 String responseString = null;
180 System.out.println("query >>>>>>> " + pdbRestRequest.toString());
184 // Execute the REST request
185 clientResponse = webResource.accept(MediaType.APPLICATION_JSON)
186 .get(clientResponseClass);
187 responseStatus = clientResponse.getStatus();
192 if (uri.toString().equals(mockQuery))
194 responseStatus = 200;
198 // FIXME - may cause unexpected exceptions for callers when mocked
199 responseStatus = 400;
203 // Check the response status and report exception if one occurs
204 switch (responseStatus)
210 responseString = mockResponse;
216 jsonObj = clientResponse.getEntity(Map.class);
220 responseString = clientResponse.getEntity(String.class);
225 throw new Exception(parseJsonExceptionString(responseString));
228 getMessageByHTTPStatusCode(responseStatus, "PDB"));
231 // Process the response and return the result to the caller.
232 return parsePDBJsonResponse(responseString, jsonObj, pdbRestRequest);
233 } catch (Exception e)
235 if (e.getMessage()==null)
239 String exceptionMsg = e.getMessage();
240 if (exceptionMsg.contains("SocketException"))
242 // No internet connection
243 throw new Exception(MessageManager.getString(
244 "exception.unable_to_detect_internet_connection"));
246 else if (exceptionMsg.contains("UnknownHostException"))
248 // The server 'www.ebi.ac.uk' is unreachable
249 throw new Exception(MessageManager.formatMessage(
250 "exception.fts_server_unreachable", "PDB Solr"));
260 * Process error response from PDB server if/when one occurs.
262 * @param jsonResponse
263 * the JSON string containing error message from the server
264 * @return the processed error message from the JSON string
266 @SuppressWarnings("unchecked")
267 public static String parseJsonExceptionString(String jsonErrorResponse)
269 StringBuilder errorMessage = new StringBuilder(
270 "\n============= PDB Rest Client RunTime error =============\n");
274 // "responseHeader":{
278 // "q":"(text:q93xj9_soltu) AND molecule_sequence:['' TO *] AND status:REL",
279 // "fl":"pdb_id,title,experimental_method,resolution",
281 // "sort":"overall_quality desc",
284 // "response":{"numFound":1,"start":0,"docs":[
286 // "experimental_method":["X-ray diffraction"],
288 // "resolution":2.46,
289 // "title":"The crystal structure of Potato ferredoxin I with 2Fe-2S cluster"}]
294 Map<String, Object> jsonObj = (Map<String, Object>) JSONUtils.parse(jsonErrorResponse);
295 Map<String, Object> errorResponse = (Map<String, Object>) jsonObj.get("error");
297 Map<String, Object> responseHeader = (Map<String, Object>) jsonObj
298 .get("responseHeader");
299 Map<String, Object> paramsObj = (Map<String, Object>) responseHeader.get("params");
300 String status = responseHeader.get("status").toString();
301 String message = errorResponse.get("msg").toString();
302 String query = paramsObj.get("q").toString();
303 String fl = paramsObj.get("fl").toString();
305 errorMessage.append("Status: ").append(status).append("\n");
306 errorMessage.append("Message: ").append(message).append("\n");
307 errorMessage.append("query: ").append(query).append("\n");
308 errorMessage.append("fl: ").append(fl).append("\n");
310 } catch (ParseException e)
314 return errorMessage.toString();
318 * Parses the JSON response string from PDB REST API. The response is dynamic
319 * hence, only fields specifically requested for in the 'wantedFields'
320 * parameter is fetched/processed
322 * @param pdbJsonResponseString
323 * the JSON string to be parsed
324 * @param pdbRestRequest
325 * the request object which contains parameters used to process the
329 public static FTSRestResponse parsePDBJsonResponse(
330 String pdbJsonResponseString, FTSRestRequest pdbRestRequest)
332 return parsePDBJsonResponse(pdbJsonResponseString,
333 (Map<String, Object>) null, pdbRestRequest);
336 @SuppressWarnings("unchecked")
337 public static FTSRestResponse parsePDBJsonResponse(
338 String pdbJsonResponseString, Map<String, Object> jsonObj,
339 FTSRestRequest pdbRestRequest)
341 FTSRestResponse searchResult = new FTSRestResponse();
342 List<FTSData> result = null;
347 jsonObj = (Map<String, Object>) JSONUtils.parse(pdbJsonResponseString);
349 Map<String, Object> pdbResponse = (Map<String, Object>) jsonObj.get("response");
350 String queryTime = ((Map<String, Object>) jsonObj.get("responseHeader"))
351 .get("QTime").toString();
352 int numFound = Integer
353 .valueOf(pdbResponse.get("numFound").toString());
354 List<Object> docs = (List<Object>) pdbResponse.get("docs");
356 result = new ArrayList<FTSData>();
360 for (Iterator<Object> docIter = docs.iterator(); docIter
363 Map<String, Object> doc = (Map<String, Object>) docIter.next();
364 result.add(getFTSData(doc, pdbRestRequest));
367 searchResult.setNumberOfItemsFound(result.size());
368 searchResult.setResponseTime(queryTime);
369 searchResult.setSearchSummary(result);
371 } catch (ParseException e)
378 public static FTSData getFTSData(Map<String, Object> pdbJsonDoc,
379 FTSRestRequest request)
382 String primaryKey = null;
384 Object[] summaryRowData;
386 SequenceI associatedSequence;
388 Collection<FTSDataColumnI> diplayFields = request.getWantedFields();
389 SequenceI associatedSeq = request.getAssociatedSequence();
391 summaryRowData = new Object[(associatedSeq != null)
392 ? diplayFields.size() + 1
393 : diplayFields.size()];
394 if (associatedSeq != null)
396 associatedSequence = associatedSeq;
397 summaryRowData[0] = associatedSequence;
401 for (FTSDataColumnI field : diplayFields)
403 //System.out.println("Field " + field);
404 String fieldData = (pdbJsonDoc.get(field.getCode()) == null) ? ""
405 : pdbJsonDoc.get(field.getCode()).toString();
406 //System.out.println("Field Data : " + fieldData);
407 if (field.isPrimaryKeyColumn())
409 primaryKey = fieldData;
410 summaryRowData[colCounter++] = primaryKey;
412 else if (fieldData == null || fieldData.isEmpty())
414 summaryRowData[colCounter++] = null;
420 summaryRowData[colCounter++] = (field.getDataType()
421 .getDataTypeClass() == Integer.class)
422 ? Integer.valueOf(fieldData)
423 : (field.getDataType()
424 .getDataTypeClass() == Double.class)
425 ? Double.valueOf(fieldData)
426 : sanitiseData(fieldData);
427 } catch (Exception e)
430 System.out.println("offending value:" + fieldData);
435 final String primaryKey1 = primaryKey;
437 final Object[] summaryRowData1 = summaryRowData;
441 public Object[] getSummaryData()
443 return summaryRowData1;
447 public Object getPrimaryKey()
453 * Returns a string representation of this object;
456 public String toString()
458 StringBuilder summaryFieldValues = new StringBuilder();
459 for (Object summaryField : summaryRowData1)
461 summaryFieldValues.append(
462 summaryField == null ? " " : summaryField.toString())
465 return summaryFieldValues.toString();
469 * Returns hash code value for this object
472 public int hashCode()
474 return Objects.hash(primaryKey1, this.toString());
478 public boolean equals(Object that)
480 return this.toString().equals(that.toString());
485 private static String sanitiseData(String data)
487 String cleanData = data.replaceAll("\\[\"", "").replaceAll("\\]\"", "")
488 .replaceAll("\\[", "").replaceAll("\\]", "")
489 .replaceAll("\",\"", ", ").replaceAll("\"", "");
494 public String getColumnDataConfigFileName()
496 return "/fts/pdb_data_columns.txt";
499 public static FTSRestClientI getInstance()
501 if (instance == null)
503 instance = new PDBFTSRestClient();
508 private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
510 public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
512 if (allDefaultDisplayedStructureDataColumns == null
513 || allDefaultDisplayedStructureDataColumns.isEmpty())
515 allDefaultDisplayedStructureDataColumns = new ArrayList<>();
516 allDefaultDisplayedStructureDataColumns
517 .addAll(super.getAllDefaultDisplayedFTSDataColumns());
519 return allDefaultDisplayedStructureDataColumns;
522 public String[] getPreferencesColumnsFor(PreferenceSource source) {
523 String[] columnNames = null;
527 columnNames = new String[] { "", "Display", "Group" };
529 case STRUCTURE_CHOOSER:
530 columnNames = new String[] { "", "Display", "Group" };
533 columnNames = new String[] { "PDB Field", "Show in search summary",
534 "Show in structure summary" };
542 public static void setMock()
544 String mockReq = "https://www.ebi.ac.uk/pdbe/search/pdb/select?wt=json&fl=pdb_id,title,experimental_method,resolution&rows=500&start=0&q=(4igk+OR+1t15+OR+4ifi+OR+1t29+OR+3pxb+OR+4y2g+OR+1y98+OR+1jnx+OR+3pxa+OR+3k0h+OR+3k0k+OR+1n5o+OR+3pxc+OR+3pxd+OR+1t2u+OR+3k15+OR+3pxe+OR+3k16+OR+4ofb+OR+3coj+OR+7lyb+OR+1t2v+OR+4y18+OR+4jlu+OR+4u4a+OR+2ing+OR+7jzv+OR+6g2i+OR+1jm7+OR+1oqa)+AND+molecule_sequence:%5B''+TO+*%5D+AND+status:REL&sort=";
545 String mockResp = "{\n"
546 + " \"responseHeader\":{\n"
550 + " \"q\":\"(4igk OR 1t15 OR 4ifi OR 1t29 OR 3pxb OR 4y2g OR 1y98 OR 1jnx OR 3pxa OR 3k0h OR 3k0k OR 1n5o OR 3pxc OR 3pxd OR 1t2u OR 3k15 OR 3pxe OR 3k16 OR 4ofb OR 3coj OR 7lyb OR 1t2v OR 4y18 OR 4jlu OR 4u4a OR 2ing OR 7jzv OR 6g2i OR 1jm7 OR 1oqa) AND molecule_sequence:['' TO *] AND status:REL\",\n"
551 + " \"fl\":\"pdb_id,title,experimental_method,resolution\",\n"
552 + " \"start\":\"0\",\n"
553 + " \"sort\":\"\",\n"
554 + " \"rows\":\"500\",\n"
555 + " \"wt\":\"json\"}},\n"
556 + " \"response\":{\"numFound\":64,\"start\":0,\"docs\":[\n"
558 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
559 + " \"pdb_id\":\"4ofb\",\n"
560 + " \"resolution\":3.05,\n"
561 + " \"title\":\"Crystal structure of human BRCA1 BRCT in complex with nonphosphopeptide inhibitor\"},\n"
563 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
564 + " \"pdb_id\":\"3pxe\",\n"
565 + " \"resolution\":2.85,\n"
566 + " \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: E1836K\"},\n"
568 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
569 + " \"pdb_id\":\"4jlu\",\n"
570 + " \"resolution\":3.5,\n"
571 + " \"title\":\"Crystal structure of BRCA1 BRCT with doubly phosphorylated Abraxas\"},\n"
573 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
574 + " \"pdb_id\":\"4y2g\",\n"
575 + " \"resolution\":2.5,\n"
576 + " \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas single phosphorylated peptide\"},\n"
578 + " \"experimental_method\":[\"Solution NMR\"],\n"
579 + " \"pdb_id\":\"1oqa\",\n"
580 + " \"title\":\"Solution structure of the BRCT-c domain from human BRCA1\"},\n"
582 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
583 + " \"pdb_id\":\"4u4a\",\n"
584 + " \"resolution\":3.51,\n"
585 + " \"title\":\"Complex Structure of BRCA1 BRCT with singly phospho Abraxas\"},\n"
587 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
588 + " \"pdb_id\":\"1t2v\",\n"
589 + " \"resolution\":3.3,\n"
590 + " \"title\":\"Structural basis of phospho-peptide recognition by the BRCT domain of BRCA1, structure with phosphopeptide\"},\n"
592 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
593 + " \"pdb_id\":\"3k15\",\n"
594 + " \"resolution\":2.8,\n"
595 + " \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
597 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
598 + " \"pdb_id\":\"1t15\",\n"
599 + " \"resolution\":1.85,\n"
600 + " \"title\":\"Crystal Structure of the Brca1 BRCT Domains in Complex with the Phosphorylated Interacting Region from Bach1 Helicase\"},\n"
602 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
603 + " \"pdb_id\":\"3k16\",\n"
604 + " \"resolution\":3.0,\n"
605 + " \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus\"},\n"
607 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
608 + " \"pdb_id\":\"1t29\",\n"
609 + " \"resolution\":2.3,\n"
610 + " \"title\":\"Crystal structure of the BRCA1 BRCT repeats bound to a phosphorylated BACH1 peptide\"},\n"
612 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
613 + " \"pdb_id\":\"1y98\",\n"
614 + " \"resolution\":2.5,\n"
615 + " \"title\":\"Structure of the BRCT repeats of BRCA1 bound to a CtIP phosphopeptide.\"},\n"
617 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
618 + " \"pdb_id\":\"4ifi\",\n"
619 + " \"resolution\":2.2,\n"
620 + " \"title\":\"Structure of human BRCA1 BRCT in complex with BAAT peptide\"},\n"
622 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
623 + " \"pdb_id\":\"3k0k\",\n"
624 + " \"resolution\":2.7,\n"
625 + " \"title\":\"Crystal Structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus.\"},\n"
627 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
628 + " \"pdb_id\":\"3k0h\",\n"
629 + " \"resolution\":2.7,\n"
630 + " \"title\":\"The crystal structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
632 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
633 + " \"pdb_id\":\"3pxd\",\n"
634 + " \"resolution\":2.8,\n"
635 + " \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: R1835P\"},\n"
637 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
638 + " \"pdb_id\":\"3pxc\",\n"
639 + " \"resolution\":2.8,\n"
640 + " \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: R1699Q\"},\n"
642 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
643 + " \"pdb_id\":\"3pxa\",\n"
644 + " \"resolution\":2.55,\n"
645 + " \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: G1656D\"},\n"
647 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
648 + " \"pdb_id\":\"1jnx\",\n"
649 + " \"resolution\":2.5,\n"
650 + " \"title\":\"Crystal structure of the BRCT repeat region from the breast cancer associated protein, BRCA1\"},\n"
652 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
653 + " \"pdb_id\":\"4igk\",\n"
654 + " \"resolution\":1.75,\n"
655 + " \"title\":\"Structure of human BRCA1 BRCT in complex with ATRIP peptide\"},\n"
657 + " \"experimental_method\":[\"Solution NMR\"],\n"
658 + " \"pdb_id\":\"1jm7\",\n"
659 + " \"title\":\"Solution structure of the BRCA1/BARD1 RING-domain heterodimer\"},\n"
661 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
662 + " \"pdb_id\":\"4jlu\",\n"
663 + " \"resolution\":3.5,\n"
664 + " \"title\":\"Crystal structure of BRCA1 BRCT with doubly phosphorylated Abraxas\"},\n"
666 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
667 + " \"pdb_id\":\"6g2i\",\n"
668 + " \"resolution\":5.9,\n"
669 + " \"title\":\"Filament of acetyl-CoA carboxylase and BRCT domains of BRCA1 (ACC-BRCT) at 5.9 A resolution\"},\n"
671 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
672 + " \"pdb_id\":\"3coj\",\n"
673 + " \"resolution\":3.21,\n"
674 + " \"title\":\"Crystal Structure of the BRCT Domains of Human BRCA1 in Complex with a Phosphorylated Peptide from Human Acetyl-CoA Carboxylase 1\"},\n"
676 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
677 + " \"pdb_id\":\"3pxb\",\n"
678 + " \"resolution\":2.5,\n"
679 + " \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: T1700A\"},\n"
681 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
682 + " \"pdb_id\":\"1t2u\",\n"
683 + " \"resolution\":2.8,\n"
684 + " \"title\":\"Structural basis of phosphopeptide recognition by the BRCT domain of BRCA1: structure of BRCA1 missense variant V1809F\"},\n"
686 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
687 + " \"pdb_id\":\"1n5o\",\n"
688 + " \"resolution\":2.8,\n"
689 + " \"title\":\"Structural consequences of a cancer-causing BRCA1-BRCT missense mutation\"},\n"
691 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
692 + " \"pdb_id\":\"4u4a\",\n"
693 + " \"resolution\":3.51,\n"
694 + " \"title\":\"Complex Structure of BRCA1 BRCT with singly phospho Abraxas\"},\n"
696 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
697 + " \"pdb_id\":\"4y2g\",\n"
698 + " \"resolution\":2.5,\n"
699 + " \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas single phosphorylated peptide\"},\n"
701 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
702 + " \"pdb_id\":\"3pxe\",\n"
703 + " \"resolution\":2.85,\n"
704 + " \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: E1836K\"},\n"
706 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
707 + " \"pdb_id\":\"4ofb\",\n"
708 + " \"resolution\":3.05,\n"
709 + " \"title\":\"Crystal structure of human BRCA1 BRCT in complex with nonphosphopeptide inhibitor\"},\n"
711 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
712 + " \"pdb_id\":\"4y18\",\n"
713 + " \"resolution\":3.5,\n"
714 + " \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas double phosphorylated peptide\"},\n"
716 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
717 + " \"pdb_id\":\"2ing\",\n"
718 + " \"resolution\":3.6,\n"
719 + " \"title\":\"X-ray Structure of the BRCA1 BRCT mutant M1775K\"},\n"
721 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
722 + " \"pdb_id\":\"1t29\",\n"
723 + " \"resolution\":2.3,\n"
724 + " \"title\":\"Crystal structure of the BRCA1 BRCT repeats bound to a phosphorylated BACH1 peptide\"},\n"
726 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
727 + " \"pdb_id\":\"1t2v\",\n"
728 + " \"resolution\":3.3,\n"
729 + " \"title\":\"Structural basis of phospho-peptide recognition by the BRCT domain of BRCA1, structure with phosphopeptide\"},\n"
731 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
732 + " \"pdb_id\":\"1t15\",\n"
733 + " \"resolution\":1.85,\n"
734 + " \"title\":\"Crystal Structure of the Brca1 BRCT Domains in Complex with the Phosphorylated Interacting Region from Bach1 Helicase\"},\n"
736 + " \"experimental_method\":[\"Solution NMR\"],\n"
737 + " \"pdb_id\":\"1jm7\",\n"
738 + " \"title\":\"Solution structure of the BRCA1/BARD1 RING-domain heterodimer\"},\n"
740 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
741 + " \"pdb_id\":\"4ifi\",\n"
742 + " \"resolution\":2.2,\n"
743 + " \"title\":\"Structure of human BRCA1 BRCT in complex with BAAT peptide\"},\n"
745 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
746 + " \"pdb_id\":\"4igk\",\n"
747 + " \"resolution\":1.75,\n"
748 + " \"title\":\"Structure of human BRCA1 BRCT in complex with ATRIP peptide\"},\n"
750 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
751 + " \"pdb_id\":\"1y98\",\n"
752 + " \"resolution\":2.5,\n"
753 + " \"title\":\"Structure of the BRCT repeats of BRCA1 bound to a CtIP phosphopeptide.\"},\n"
755 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
756 + " \"pdb_id\":\"3k15\",\n"
757 + " \"resolution\":2.8,\n"
758 + " \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
760 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
761 + " \"pdb_id\":\"3k0k\",\n"
762 + " \"resolution\":2.7,\n"
763 + " \"title\":\"Crystal Structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus.\"},\n"
765 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
766 + " \"pdb_id\":\"3k16\",\n"
767 + " \"resolution\":3.0,\n"
768 + " \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus\"},\n"
770 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
771 + " \"pdb_id\":\"3k0h\",\n"
772 + " \"resolution\":2.7,\n"
773 + " \"title\":\"The crystal structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
775 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
776 + " \"pdb_id\":\"4y18\",\n"
777 + " \"resolution\":3.5,\n"
778 + " \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas double phosphorylated peptide\"},\n"
780 + " \"experimental_method\":[\"X-ray diffraction\"],\n"
781 + " \"pdb_id\":\"3coj\",\n"
782 + " \"resolution\":3.21,\n"
783 + " \"title\":\"Crystal Structure of the BRCT Domains of Human BRCA1 in Complex with a Phosphorylated Peptide from Human Acetyl-CoA Carboxylase 1\"},\n"
785 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
786 + " \"pdb_id\":\"7jzv\",\n"
787 + " \"resolution\":3.9,\n"
788 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
790 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
791 + " \"pdb_id\":\"7jzv\",\n"
792 + " \"resolution\":3.9,\n"
793 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
795 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
796 + " \"pdb_id\":\"7lyb\",\n"
797 + " \"resolution\":3.28,\n"
798 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
800 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
801 + " \"pdb_id\":\"7lyb\",\n"
802 + " \"resolution\":3.28,\n"
803 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
805 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
806 + " \"pdb_id\":\"7lyb\",\n"
807 + " \"resolution\":3.28,\n"
808 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
810 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
811 + " \"pdb_id\":\"7jzv\",\n"
812 + " \"resolution\":3.9,\n"
813 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
815 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
816 + " \"pdb_id\":\"7lyb\",\n"
817 + " \"resolution\":3.28,\n"
818 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
820 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
821 + " \"pdb_id\":\"7jzv\",\n"
822 + " \"resolution\":3.9,\n"
823 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
825 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
826 + " \"pdb_id\":\"7lyb\",\n"
827 + " \"resolution\":3.28,\n"
828 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
830 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
831 + " \"pdb_id\":\"7jzv\",\n"
832 + " \"resolution\":3.9,\n"
833 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
835 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
836 + " \"pdb_id\":\"7lyb\",\n"
837 + " \"resolution\":3.28,\n"
838 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
840 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
841 + " \"pdb_id\":\"7lyb\",\n"
842 + " \"resolution\":3.28,\n"
843 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
845 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
846 + " \"pdb_id\":\"7lyb\",\n"
847 + " \"resolution\":3.28,\n"
848 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
850 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
851 + " \"pdb_id\":\"7jzv\",\n"
852 + " \"resolution\":3.9,\n"
853 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
855 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
856 + " \"pdb_id\":\"6g2i\",\n"
857 + " \"resolution\":5.9,\n"
858 + " \"title\":\"Filament of acetyl-CoA carboxylase and BRCT domains of BRCA1 (ACC-BRCT) at 5.9 A resolution\"},\n"
860 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
861 + " \"pdb_id\":\"7jzv\",\n"
862 + " \"resolution\":3.9,\n"
863 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
865 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
866 + " \"pdb_id\":\"7lyb\",\n"
867 + " \"resolution\":3.28,\n"
868 + " \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
870 + " \"experimental_method\":[\"Electron Microscopy\"],\n"
871 + " \"pdb_id\":\"7jzv\",\n"
872 + " \"resolution\":3.9,\n"
873 + " \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"}]\n"
875 createMockFTSRestClient((FTSRestClient)getInstance(), mockReq, mockResp);