|
21 | 21 | import java.awt.event.KeyListener; |
22 | 22 | import java.awt.event.MouseAdapter; |
23 | 23 | import java.awt.event.MouseEvent; |
| 24 | +import java.io.IOException; |
| 25 | +import java.io.StringReader; |
| 26 | +import java.io.InputStream; |
| 27 | +import java.net.HttpURLConnection; |
24 | 28 | import java.net.URL; |
25 | 29 | import java.net.URLEncoder; |
| 30 | +import java.nio.charset.StandardCharsets; |
26 | 31 | import java.time.Duration; |
27 | 32 | import java.util.ArrayList; |
28 | 33 | import java.util.Collections; |
|
41 | 46 | import javax.swing.tree.DefaultTreeCellRenderer; |
42 | 47 | import javax.swing.tree.DefaultTreeModel; |
43 | 48 | import javax.swing.tree.TreePath; |
| 49 | +import javax.xml.parsers.*; |
| 50 | +import org.w3c.dom.*; |
| 51 | +import java.io.File; |
44 | 52 |
|
45 | 53 | import cbit.vcell.client.server.DynamicClientProperties; |
46 | 54 | import org.sbpax.util.StringUtil; |
| 55 | +import org.vcell.util.ClientTaskStatusSupport; |
47 | 56 | import org.vcell.pathway.PathwayModel; |
48 | 57 | import org.vcell.pathway.persistence.PathwayIOUtil; |
49 | 58 | import org.vcell.pathway.persistence.RDFXMLContext; |
|
66 | 75 | import cbit.vcell.client.task.ClientTaskDispatcher; |
67 | 76 | import cbit.vcell.desktop.BioModelNode; |
68 | 77 | import cbit.vcell.resource.PropertyLoader; |
| 78 | +import org.xml.sax.InputSource; |
69 | 79 |
|
70 | 80 | @SuppressWarnings("serial") |
71 | 81 | public class BioModelEditorPathwayCommonsPanel extends DocumentEditorSubPanel { |
@@ -182,17 +192,30 @@ void addSearchResponse(String searchText, Element searchResponse) { |
182 | 192 | } else { |
183 | 193 | // pathwaysList = new ArrayList<Pathway>(); |
184 | 194 | pathwaysList.clear(); |
185 | | - List<Element> hitElements = DOMUtil.childElements(searchResponse, "search_hit"); |
186 | | - int pathwayCount = 0; |
187 | | - for(Element hitElement : hitElements) { |
188 | | - Hit hit = new Hit(hitElement); |
189 | | - List<Pathway> pL = hit.pathways(); // pathway |
190 | | - int numPathways = pL.size(); |
191 | | - if (numPathways > 0) { |
192 | | - for (Pathway pathway: pL) { |
193 | | - pathway.setOrganism(hit.organism()); |
194 | | - if(!pathwaysList.contains(pathway)) { |
195 | | - pathwaysList.add(pathway); |
| 195 | + |
| 196 | + NodeList hitNodes = searchResponse.getElementsByTagName("searchHit"); |
| 197 | + System.out.println("Found " + hitNodes.getLength() + " hits\n"); |
| 198 | + |
| 199 | + |
| 200 | + for (int i = 0; i < hitNodes.getLength(); i++) { |
| 201 | + Element hitElement = (Element) hitNodes.item(i); |
| 202 | + String uri = Hit.getText(hitElement, "uri"); |
| 203 | + if (uri.contains("reactome")) { |
| 204 | + |
| 205 | + NodeList responses = hitElement.getElementsByTagName("pathway"); |
| 206 | + if(responses.getLength() == 0) { |
| 207 | + continue; // we skip some malformed entries |
| 208 | + } |
| 209 | + Hit hit = new Hit(hitElement); |
| 210 | + |
| 211 | + List<Pathway> pL = hit.pathways(); // pathway |
| 212 | + int numPathways = pL.size(); |
| 213 | + if (numPathways > 0) { |
| 214 | + for (Pathway pathway : pL) { |
| 215 | + // pathway.setOrganism(hit.organism()); |
| 216 | + if (!pathwaysList.contains(pathway)) { |
| 217 | + pathwaysList.add(pathway); |
| 218 | + } |
196 | 219 | } |
197 | 220 | } |
198 | 221 | } |
@@ -254,6 +277,9 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, |
254 | 277 | // <html><body><p style="color:red">This is some text!</p></body></html> |
255 | 278 | // <u> = underlined, <b> = bold |
256 | 279 | String dbName = pathway.dataSource().name(); |
| 280 | + if(dbName.startsWith("pc14:")) { |
| 281 | + dbName = dbName.replace("pc14:", ""); |
| 282 | + } |
257 | 283 | if(dbName.contains("Interaction Database")) { |
258 | 284 | dbName = dbName.replace("Interaction Database", "Db"); |
259 | 285 | } |
@@ -332,33 +358,24 @@ public void showPathway() { |
332 | 358 | AsynchClientTask task1 = new AsynchClientTask("Importing pathway '" + pathway.name() + "'", AsynchClientTask.TASKTYPE_NONSWING_BLOCKING) { |
333 | 359 | @Override |
334 | 360 | public void run(final Hashtable<String, Object> hashTable) throws Exception { |
335 | | - final URL url = new URL(DynamicClientProperties.getDynamicClientProperties().getProperty(PropertyLoader.PATHWAY_WEB_DO_URL) + "?" |
336 | | - + PathwayCommonsKeyword.cmd + "=" + PathwayCommonsKeyword.get_record_by_cpath_id |
337 | | - + "&" + PathwayCommonsKeyword.version + "=" + PathwayCommonsVersion.v2.name |
338 | | - + "&" + PathwayCommonsKeyword.q + "=" + pathway.primaryId() |
339 | | - + "&" + PathwayCommonsKeyword.output + "=" + PathwayCommonsKeyword.biopax); |
340 | | - |
341 | | - System.out.println(url.toString()); |
| 361 | + |
| 362 | + String id = extractReactomeId(pathway.primaryId()); |
| 363 | + final URL url = new URL(" https://reactome.org/ReactomeRESTfulAPI/RESTfulWS/biopaxExporter/Level2/" + id); |
| 364 | + |
| 365 | + System.out.println(url.toString()); |
342 | 366 | String ERROR_CODE_TAG = "error_code"; |
343 | | -// String ERROR_MSG_TAG = "error_msg"; |
344 | | - final String contentString = ClientDownloader.downloadBytes(url, Duration.ofSeconds(10)); |
| 367 | + |
| 368 | + String contentString = ClientDownloader.downloadBytes(url, Duration.ofSeconds(20)); |
| 369 | + |
345 | 370 | org.jdom2.Document jdomDocument = XmlUtil.stringToXML(contentString, null); |
346 | 371 | org.jdom2.Element rootElement = jdomDocument.getRootElement(); |
347 | 372 | String errorCode = rootElement.getChildText(ERROR_CODE_TAG); |
348 | 373 | if (errorCode != null){ |
349 | 374 | throw new RuntimeException("Failed to access " + url + " \n\nPlease try again."); |
350 | 375 | } |
351 | | - |
352 | | -// String xmlText = StringUtil.textFromInputStream(connection.getInputStream()); |
353 | | -// PathwayReader pathwayReader = new PathwayReader(); |
354 | | -// org.jdom2.Document jdomDocument = XmlUtil.stringToXML(xmlText, null); |
355 | | - |
356 | | -// String xmlText = StringUtil.textFromInputStream(connection.getInputStream(), "UTF-8"); |
357 | | -// PathwayReader pathwayReader = new PathwayReader(); |
358 | | -// org.jdom2.Document jdomDocument = XmlUtil.stringToXML(xmlText, "UTF-8"); |
359 | | - |
360 | | - PathwayModel pathwayModel = PathwayIOUtil.extractPathwayFromJDOM(jdomDocument, new RDFXMLContext(), |
361 | | - getClientTaskStatusSupport()); |
| 376 | + |
| 377 | + ClientTaskStatusSupport ctss = getClientTaskStatusSupport(); |
| 378 | + PathwayModel pathwayModel = PathwayIOUtil.extractPathwayFromJDOM(jdomDocument, new RDFXMLContext(), ctss); |
362 | 379 | PathwayData pathwayData = new PathwayData(pathway.name(), pathwayModel); |
363 | 380 | hashTable.put("pathwayData", pathwayData); |
364 | 381 | } |
@@ -410,27 +427,59 @@ public void search() { |
410 | 427 |
|
411 | 428 | @Override |
412 | 429 | public void run(Hashtable<String, Object> hashTable) throws Exception { |
413 | | - URL url = new URL(DynamicClientProperties.getDynamicClientProperties().getProperty(PropertyLoader.PATHWAY_WEB_DO_URL) + "?" |
414 | | - + PathwayCommonsKeyword.cmd + "=" + PathwayCommonsKeyword.search |
415 | | - + "&" + PathwayCommonsKeyword.version + "=" + PathwayCommonsVersion.v2.name |
416 | | - + "&" + PathwayCommonsKeyword.q + "=" + URLEncoder.encode(searchText, "UTF-8") |
417 | | - + "&" + PathwayCommonsKeyword.maxHits + "=" + 14 |
418 | | - + "&" + PathwayCommonsKeyword.output + "=" + PathwayCommonsKeyword.xml); |
419 | | - System.out.println(url); |
420 | | - String responseContent = ClientDownloader.downloadBytes(url, Duration.ofSeconds(10)); |
421 | | - Document document = DOMUtil.parse(responseContent); |
422 | | - |
423 | | - Element errorElement = DOMUtil.firstChildElement(document, "error"); |
424 | | - if (errorElement != null) { |
425 | | -// String xml = DOMUtil.firstChildContent(document, "error"); |
426 | | - throw new RuntimeException(errorElement.getTextContent()); |
427 | | - } |
428 | | - Element searchResponse = DOMUtil.firstChildElement(document, "search_response"); |
429 | | - if (searchResponse != null) { |
430 | | -// String xml = DOMUtil.firstChildContent(document, "search_response"); |
431 | | -// System.out.println(xml); |
432 | | - hashTable.put("searchResponse", searchResponse); |
| 430 | + |
| 431 | + // Encode the quoted term: "%22insulin%22" |
| 432 | + String encodedQ = URLEncoder.encode('"' + searchText + '"', StandardCharsets.UTF_8.name()); |
| 433 | + String uri = "https://www.pathwaycommons.org/pc2/search?" |
| 434 | + + "q=" + encodedQ |
| 435 | + + "&type=pathway"; |
| 436 | + System.out.println(uri); |
| 437 | + |
| 438 | + HttpURLConnection conn = (HttpURLConnection)new URL(uri).openConnection(); |
| 439 | + conn.setRequestProperty("Accept", "application/xml"); |
| 440 | + |
| 441 | + Element searchResponse = null; |
| 442 | + try (InputStream in = conn.getInputStream()) { |
| 443 | + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); |
| 444 | + // Prevent XXE attacks in XML parsing, suggested by GitHub Advanced Security bot |
| 445 | + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); |
| 446 | + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); |
| 447 | + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); |
| 448 | + dbf.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true); |
| 449 | + DocumentBuilder db = dbf.newDocumentBuilder(); |
| 450 | + Document doc = db.parse(in); |
| 451 | + doc.getDocumentElement().normalize(); |
| 452 | + |
| 453 | + searchResponse = doc.getDocumentElement(); |
| 454 | + System.out.println("Root element: " + searchResponse.getNodeName()); |
433 | 455 | } |
| 456 | + |
| 457 | + // let's make sure we have some searchHit elements |
| 458 | + NodeList hitNodes = searchResponse.getElementsByTagName("searchHit"); |
| 459 | + System.out.println("Found " + hitNodes.getLength() + " hits\n"); |
| 460 | + hashTable.put("searchResponse", searchResponse); |
| 461 | + |
| 462 | +// for (int i = 0; i < hitNodes.getLength(); i++) { |
| 463 | +// Element hit = (Element) hitNodes.item(i); |
| 464 | +// |
| 465 | +// String uri = getText(hit, "uri"); |
| 466 | +// String name = getText(hit, "name"); |
| 467 | +// String source = getText(hit, "dataSource"); |
| 468 | +// String organism = getText(hit, "organism"); |
| 469 | +// String participants = getText(hit, "numParticipants"); |
| 470 | +// String processes = getText(hit, "numProcesses"); |
| 471 | +// |
| 472 | +// System.out.println("Pathway: " + name); |
| 473 | +// System.out.println(" URI: " + uri); |
| 474 | +// System.out.println(" Source: " + source); |
| 475 | +// System.out.println(" Organism: " + (organism != null ? organism : "[unspecified]")); |
| 476 | +// System.out.println(" Participants: " + participants + " | Processes: " + processes); |
| 477 | +// System.out.println(); |
| 478 | +// |
| 479 | +// if(uri.contains("reactome")) { |
| 480 | +// hashTable.put("searchHit", hit); |
| 481 | +// } |
| 482 | +// } |
434 | 483 | } |
435 | 484 | }; |
436 | 485 | AsynchClientTask task2 = new AsynchClientTask("showing", AsynchClientTask.TASKTYPE_SWING_BLOCKING) { |
@@ -509,8 +558,7 @@ private void initialize() { |
509 | 558 | gbc.insets = new Insets(4,4,4,4); |
510 | 559 | gbc.fill = GridBagConstraints.BOTH; |
511 | 560 | add(new JScrollPane(responseTree), gbc); |
512 | | - |
513 | | - |
| 561 | + |
514 | 562 | gridy ++; |
515 | 563 | CollapsiblePanel filterPanel = new CollapsiblePanel("Filter", true); |
516 | 564 | filterPanel.getContentPanel().setLayout(new GridBagLayout()); |
@@ -574,7 +622,6 @@ private void initialize() { |
574 | 622 | // optionsPanel.expand(false); |
575 | 623 | // add(optionsPanel, gbc); |
576 | 624 |
|
577 | | - |
578 | 625 | gridy ++; |
579 | 626 | gbc = new GridBagConstraints(); |
580 | 627 | gbc.gridx = 0; |
@@ -636,4 +683,14 @@ public static boolean isPathwayObject(Object object) { |
636 | 683 | @Override |
637 | 684 | protected void onSelectedObjectsChange(Object[] selectedObjects) { |
638 | 685 | } |
| 686 | + |
| 687 | + public static String extractReactomeId(String primaryId) { |
| 688 | + final String PREFIX = "R-HSA-"; |
| 689 | + int index = primaryId.indexOf(PREFIX); |
| 690 | + if (index == -1) { |
| 691 | + throw new IllegalArgumentException("Malformed primaryId: missing 'R-HSA-' prefix"); |
| 692 | + } |
| 693 | + return primaryId.substring(index + PREFIX.length()); |
| 694 | + } |
| 695 | + |
639 | 696 | } |
0 commit comments