001package org.biopax.paxtools.io; 002 003import org.apache.commons.lang.StringEscapeUtils; 004import org.apache.commons.logging.Log; 005import org.apache.commons.logging.LogFactory; 006import org.biopax.paxtools.controller.AbstractPropertyEditor; 007import org.biopax.paxtools.controller.PropertyEditor; 008import org.biopax.paxtools.controller.SimpleEditorMap; 009import org.biopax.paxtools.model.BioPAXElement; 010import org.biopax.paxtools.model.BioPAXFactory; 011import org.biopax.paxtools.model.BioPAXLevel; 012import org.biopax.paxtools.model.Model; 013import org.biopax.paxtools.model.level3.BiochemicalPathwayStep; 014import org.biopax.paxtools.model.level3.Named; 015import org.biopax.paxtools.util.BioPaxIOException; 016import org.biopax.paxtools.util.IllegalBioPAXArgumentException; 017 018import javax.xml.stream.XMLInputFactory; 019import javax.xml.stream.XMLStreamException; 020import javax.xml.stream.XMLStreamReader; 021import java.io.*; 022import java.util.*; 023 024import static javax.xml.stream.XMLStreamConstants.*; 025 026/** 027 * Simple BioPAX reader/writer. 028 * 029 * This class provides a JAXP based I/O handler. As compared to Jena based implementation it offers ~10x performance, 030 * significantly less memory requirements when reading large files and a lightweight deployement. It, however, 031 * is not as robust as the Jena based reader and can not read non-RDF/XML OWL formats or non-UTF encodings.For those, 032 * you might want to use the JenaIOHandler class 033 */ 034public final class SimpleIOHandler extends BioPAXIOHandlerAdapter 035{ 036 private static final Log log = LogFactory.getLog(SimpleIOHandler.class); 037 038 private XMLStreamReader r; 039 040 boolean propertyContext = false; 041 042 private List<Triple> triples; 043 044 private boolean mergeDuplicates; 045 046 private static final String owlNS = "http://www.w3.org/2002/07/owl#"; 047 048 private static final String xsdNS = "http://www.w3.org/2001/XMLSchema#"; 049 050 private static final String rdfNS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; 051 052 private static final String RDF_ID = "rdf:ID=\""; 053 054 private static final String RDF_about = "rdf:about=\""; 055 056 private static final String newline = System.getProperty("line.separator"); 057 058 private static final String close = "\">"; 059 060 private boolean normalizeNameSpaces; 061 062 private boolean absoluteUris; 063 064 065 // --------------------------- CONSTRUCTORS --------------------------- 066 067 /** 068 * Basic constructor, defaults to Level 3 and default BioPAXFactory 069 */ 070 public SimpleIOHandler() 071 { 072 this(null, null); 073 } 074 075 /** 076 * Basic constructor, defaults to level.defaultFactory 077 * @param level BioPAXLevel to handle. 078 */ 079 public SimpleIOHandler(BioPAXLevel level) 080 { 081 this(level.getDefaultFactory(), level); 082 } 083 084 /** 085 * Full constructor 086 * @param factory to create BioPAX objects 087 * @param level BioPAX level to handle. 088 */ 089 public SimpleIOHandler(BioPAXFactory factory, BioPAXLevel level) 090 { 091 super(factory, level); 092 normalizeNameSpaces = true; 093 mergeDuplicates = false; 094 } 095 096 /** 097 * If set to true, the reader will merge duplicate individuals, i.e. individuals that has the same ID. Otherwise 098 * it will throw an exception. By default it is set to false. 099 * @param mergeDuplicates true/false 100 */ 101 public void mergeDuplicates(boolean mergeDuplicates) 102 { 103 this.mergeDuplicates = mergeDuplicates; 104 } 105 106 /** 107 * If set to true, property editors will check restrictions at the subclass level and throw an exception if 108 * violated. This is true by default. 109 * 110 * WARNING: This is a static parameter and will change behaviour for the whole thread. Do not change unless you 111 * need to read a (relatively exotic) BioPAX export that violates subclass level restrictions. 112 * @param checkRestrictions true/false 113 */ 114 public void checkRestrictions(boolean checkRestrictions) 115 { 116 AbstractPropertyEditor.checkRestrictions.set(checkRestrictions); 117 } 118 // -------------------------- OTHER METHODS -------------------------- 119 120 /** 121 * This method resets the editor map. Editor maps are used to map property names to property editors. Resetting the 122 * editor map might be required to switch between levels. 123 */ 124 @Override 125 protected void resetEditorMap() 126 { 127 setEditorMap(SimpleEditorMap.get(this.getLevel())); // was 'level' - bug! 128 } 129 130 /** 131 * This may be required for external applications to access the specific information (e.g., 132 * location) when reporting XML exceptions. 133 * @return current XML stream state summary 134 */ 135 public String getXmlStreamInfo() 136 { 137 StringBuilder sb = new StringBuilder(); 138 139 int event = r.getEventType(); 140 if (event == START_ELEMENT || event == END_ELEMENT || event == ENTITY_REFERENCE) 141 { 142 sb.append(r.getLocalName()); 143 } 144 145 if (r.getLocation() != null) 146 { 147 sb.append(" line "); 148 sb.append(r.getLocation().getLineNumber()); 149 sb.append(" column "); 150 sb.append(r.getLocation().getColumnNumber()); 151 } 152 153 return sb.toString(); 154 } 155 156 157 @Override protected void init(InputStream in) 158 { 159 try 160 { 161 XMLInputFactory xmlf = XMLInputFactory.newInstance(); 162 //this is to return string with encoded chars as one event (not splitting) 163 xmlf.setProperty("javax.xml.stream.isCoalescing", true); 164 r = xmlf.createXMLStreamReader(in); 165 166 triples = new LinkedList<Triple>(); 167 168 } 169 catch (XMLStreamException e) 170 { 171 //e.printStackTrace(); 172 throw new BioPaxIOException(e.getClass().getSimpleName() + " " + e.getMessage() + "; " + e.getLocation()); 173 } 174 175 } 176 177 @Override protected void reset(InputStream in) 178 { 179 180 this.triples=null; 181 try 182 { 183 r.close(); 184 } 185 catch (XMLStreamException e) 186 { 187 throw new RuntimeException("Can't close the stream"); 188 } 189 r=null; 190 super.reset(in); 191 } 192 193 @Override protected Map<String, String> readNameSpaces() 194 { 195 Map<String, String> ns = new HashMap<String, String>(); 196 try 197 { 198 if (r.getEventType() == START_DOCUMENT) 199 { 200 r.next(); 201 } else 202 { 203 throw new BioPaxIOException("Unexpected element at start"); 204 } 205 206 // Skip any comment before we read the RDF headers 207 while (r.getEventType() == COMMENT) 208 { 209 r.next(); 210 } 211 212 if (r.getEventType() != START_ELEMENT) 213 { 214 throw new BioPaxIOException("Unexpected element at start: " + r.getEventType()); 215 } 216 217 if (!r.getLocalName().equalsIgnoreCase("rdf")) 218 { 219 throw new BioPaxIOException("Unexpected element at start: " + r.getLocalName()); 220 } 221 222 int count = r.getNamespaceCount(); 223 for (int i = 0; i < count; i++) 224 { 225 String pre = r.getNamespacePrefix(i); 226 if (pre == null) 227 { 228 pre = ""; 229 } 230 String namespace = r.getNamespaceURI(pre); 231 232 ns.put(pre, namespace); 233 } 234 235 base = null; 236 for (int i = 0; i < r.getAttributeCount(); i++) 237 { 238 if ("base".equalsIgnoreCase(r.getAttributeLocalName(i)) && 239 "xml".equalsIgnoreCase(r.getAttributePrefix(i))) 240 { 241 base = r.getAttributeValue(i); 242 } 243 } 244 } 245 catch (XMLStreamException e) 246 { 247 throw new BioPaxIOException(e.getClass().getSimpleName() + " " + e.getMessage() + "; " + e.getLocation()); 248 } 249 return ns; 250 251 } 252 253 @Override protected void createAndBind(Model model) 254 { 255 try 256 { 257 int type; 258 while ((type = r.getEventType()) != END_DOCUMENT) 259 { 260 switch (type) 261 { 262 case START_ELEMENT: 263 if (BioPAXLevel.isInBioPAXNameSpace(r.getName().getNamespaceURI())) 264 { 265 String lname = r.getLocalName(); 266 BioPAXLevel level = getLevel(); 267 Class<? extends BioPAXElement> clazz; 268 try 269 { 270 clazz = level.getInterfaceForName(lname); 271 } 272 catch (IllegalBioPAXArgumentException e) 273 { 274 log.fatal("Unknown BioPAX element location " + lname + " at " + r.getLocation()); 275 throw e; // for backward compatibility 276 } 277 if (this.getFactory().canInstantiate(clazz)) 278 { 279 processIndividual(model); 280 } else 281 { 282 if (log.isTraceEnabled()) 283 { 284 log.trace("Ignoring element: " + lname); 285 } 286 skip(); 287 } 288 289 } 290 break; 291 case CHARACTERS: 292 if (log.isTraceEnabled()) 293 { 294 StringBuilder sb = new StringBuilder("Ignoring text "); 295 if (r.hasName()) sb.append(r.getLocalName()); 296 if (r.hasText()) sb.append(r.getText()); 297 log.trace(sb.toString()); 298 } 299 break; 300 case END_ELEMENT: 301 if (log.isTraceEnabled()) 302 { 303 log.trace(r); 304 } 305 break; 306 default: 307 if (log.isTraceEnabled()) 308 { 309 log.trace("Test this!:" + type); 310 } //TODO 311 } 312 r.next(); 313 314 } 315 r.close(); 316 } 317 catch (XMLStreamException e) 318 { 319 throw new BioPaxIOException(e.getClass().getSimpleName() + " " + e.getMessage() + "; " + e.getLocation()); 320 } 321 322 for (Triple triple : triples) 323 { 324 try 325 { 326 bindValue(triple, model); 327 } 328 catch (IllegalBioPAXArgumentException e) 329 { 330 log.warn("Binding " + e); 331 } 332 } 333 334 } 335 336 /** 337 * Binds property. 338 * 339 * This method also throws exceptions related to binding. 340 * @param triple A java object that represents an RDF Triple - domain-property-range. 341 * @param model that is being populated. 342 */ 343 private void bindValue(Triple triple, Model model) 344 { 345 if (log.isDebugEnabled()) 346 { 347 log.debug(triple); 348 } 349 BioPAXElement domain = model.getByID(triple.domain); 350 351 PropertyEditor editor = this.getEditorMap().getEditorForProperty(triple.property, domain.getModelInterface()); 352 353 bindValue(triple.range, editor, domain, model); 354 } 355 356 357 private String processIndividual(Model model) throws XMLStreamException 358 { 359 String s = r.getLocalName(); 360 String id; 361 try 362 { 363 id = getId(); 364 } 365 catch (NullPointerException e) 366 { 367 throw new BioPaxIOException("Error processing individual " + s + ". rdf:ID or rdf:about not found!", e); 368 } 369 370 if (factory.canInstantiate((level.getInterfaceForName(s)))) 371 { 372 BioPAXElement bpe = model.getByID(id); 373 if (!mergeDuplicates || bpe == null) 374 { 375 createBpe(s, id, model); //throws an exception when (mergeDuplicates==false && bpe!=null) 376 } else if(!s.equals(bpe.getModelInterface().getSimpleName())) { 377 //i.e., type mismatch, 378 //whereas (mergeDuplicates==true && bpe != null) is true already - 379 throw new BioPaxIOException(String.format("processIndividual: " + 380 "despite mergeDuplicates is True, failed/skipped creating an instance " + 381 "of %s, URI:%s, because previously added object (same URI) was of different type: %s", 382 s, id, bpe.getModelInterface().getSimpleName())); 383 } 384 } else { 385 if (r.hasText()) 386 { 387 log.warn("Unknown class :" + r.getText()); 388 } else 389 { 390 log.warn("Unknown class :" + r); 391 } 392 skip(); 393 } 394 propertyContext = true; 395 r.next(); 396 while (r.getEventType() != END_ELEMENT) 397 { 398 if (r.getEventType() == START_ELEMENT) 399 { 400 processProperty(model, id); 401 propertyContext = true; 402 403 } 404 r.next(); 405 } 406 return id; 407 } 408 409 private void createBpe(String s, String id, Model model) 410 { 411 BioPAXElement bpe = factory.create(s, id); 412 model.add(bpe); 413 } 414 415 private void skip() throws XMLStreamException 416 { 417 int depth = 1; 418 while (!(r.getEventType() == END_ELEMENT && depth == 0)) 419 { 420 r.next(); 421 switch (r.getEventType()) 422 { 423 case START_ELEMENT: 424 depth++; 425 break; 426 case END_ELEMENT: 427 depth--; 428 break; 429 } 430 } 431 } 432 433 public String getId() 434 { 435 String id = r.getAttributeValue(rdf, "ID"); 436 if (id == null) 437 { 438 id = r.getAttributeValue(rdf, "about"); 439 if (id.startsWith("#")) 440 { 441 id = base + id.substring(1, id.length()); 442 443 } 444 } else if (base != null) 445 { 446 id = base + id; 447 } 448 449 return id; 450 } 451 452 private void processProperty(Model model, String ownerID) throws XMLStreamException 453 { 454 if (rdfs.equals(r.getNamespaceURI()) && "comment".equals(r.getLocalName())) 455 { 456 BioPAXElement paxElement = model.getByID(ownerID); 457 AbstractPropertyEditor commentor = getRDFCommentEditor(paxElement); 458 r.next(); 459 assert r.getEventType() == CHARACTERS; 460 String text = r.getText(); 461 commentor.setValueToBean(text, paxElement); 462 log.warn("rdfs:comment is converted into the bp:comment; " + 463 "however, this can be overridden " + 464 "if there exists another bp:comment (element: " + 465 paxElement.getRDFId() + " text: " + text + ")"); 466 gotoEndElement(); 467 } else if (bp != null && bp.equals(r.getNamespaceURI())) 468 { 469 String property = r.getLocalName(); 470 String resource = r.getAttributeValue(rdf, "resource"); 471 if (resource != null) 472 { 473 if (resource.startsWith("#")) 474 { 475 resource = (base == null ? "" : base) + resource.substring(1, resource.length()); 476 } 477 gotoEndElement(); 478 } else 479 { 480 r.next(); 481 boolean found = false; 482 while (r.getEventType() != END_ELEMENT) 483 { 484 if (!found && r.getEventType() == CHARACTERS) 485 { 486 StringBuilder buff = new StringBuilder(r.getText()); 487 r.next(); 488 while (r.getEventType() == CHARACTERS) 489 { 490 buff.append(r.getText()); 491 r.next(); 492 } 493 resource = buff.toString(); 494 495 } else if (r.getEventType() == START_ELEMENT) 496 { 497 propertyContext = false; 498 resource = processIndividual(model); 499 found = true; 500 r.next(); 501 } else r.next(); 502 } 503 resource = (!found && resource != null) ? resource.replaceAll("[\n\r\t ]+", " ") : resource; 504 } 505 506 log.trace("setting = " + resource); 507 triples.add(new Triple(ownerID, resource, property)); 508 propertyContext = false; 509 } else 510 { 511 log.trace("ignoring unknown element " + 512 r.getNamespaceURI() + r.getLocalName()); 513 gotoEndElement(); 514 } 515 516 } 517 518 private void gotoEndElement() throws XMLStreamException 519 { 520 while (r.getEventType() != END_ELEMENT) 521 { 522 r.next(); 523 } 524 } 525 526 527 public class Triple 528 { 529 public String domain, range, property; 530 531 private Triple(String domain, String range, String property) 532 { 533 this.domain = domain; 534 this.range = range; 535 this.property = property; 536 537 } 538 539 @Override 540 public String toString() 541 { 542 return String.format("domain: %s, property: %s, range: %s", domain, property, range); 543 } 544 545 } 546 547 548 /** 549 * Converts a model into BioPAX (OWL) format, and writes it into 550 * the outputStream. Saved data can be then read via {@link BioPAXIOHandler} 551 * interface (e.g., {@link SimpleIOHandler}). 552 * 553 * Note: When the model is incomplete (i.e., contains elements that refer externals, 554 * dangling BioPAX elements) and is exported by this method, it works; however one 555 * will find corresponding object properties set to NULL later, 556 * after converting such data back to Model. 557 * 558 * Note: if the model is very very large, and the output stream is a byte array stream, 559 * then you can eventually get OutOfMemoryError "Requested array size exceeds VM limit" 560 * (max. array size is 2Gb) 561 * 562 * @param model model to be converted into OWL format 563 * @param outputStream output stream into which the output will be written 564 * @throws BioPaxIOException in case of I/O problems 565 */ 566 public void convertToOWL(Model model, OutputStream outputStream) 567 { 568 initializeExporter(model); 569 570 try 571 { 572 Writer out = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8")); 573 writeObjects(out, model); 574 out.close(); 575 } 576 catch (IOException e) 577 { 578 throw new BioPaxIOException("Cannot convert to OWL!", e); 579 } 580 } 581 582 583 /** 584 * Writes the XML representation of individual BioPAX element that 585 * is BioPAX-like but only for display or debug purpose (incomplete). 586 * 587 * Note: use {@link BioPAXIOHandler#convertToOWL(org.biopax.paxtools.model.Model, java.io.OutputStream)} 588 * convertToOWL(org.biopax.paxtools.model.Model, Object)} instead 589 * if you have a model and want to save and later restore it. 590 * @param out output 591 * @param bean BioPAX object 592 * @throws IOException when the output writer throws 593 */ 594 public void writeObject(Writer out, BioPAXElement bean) throws IOException 595 { 596 String name = "bp:" + bean.getModelInterface().getSimpleName(); 597 writeIDLine(out, bean, name); 598 599 Set<PropertyEditor> editors = editorMap.getEditorsOf(bean); 600 if (editors == null || editors.isEmpty()) 601 { 602 log.info("no editors for " + bean.getRDFId() + " | " + bean.getModelInterface().getSimpleName()); 603 out.write(newline + "</" + name + ">"); 604 return; 605 } 606 607 for (PropertyEditor editor : editors) 608 { 609 Set value = editor.getValueFromBean(bean); //is never null 610 for (Object valueElement : value) 611 { 612 if (!editor.isUnknown(valueElement)) writeStatementFor(bean, editor, valueElement, out); 613 } 614 } 615 616 out.write(newline + "</" + name + ">"); 617 } 618 619 620 private void writeObjects(Writer out, Model model) throws IOException 621 { 622 writeHeader(out); 623 624 Set<BioPAXElement> bioPAXElements = model.getObjects(); 625 for (BioPAXElement bean : bioPAXElements) 626 { 627 writeObject(out, bean); 628 } 629 630 out.write(newline + "</rdf:RDF>"); 631 } 632 633 634 private void writeStatementFor(BioPAXElement bean, PropertyEditor editor, Object value, Writer out) 635 throws IOException 636 { 637 assert (bean != null && editor != null && value != null); 638 639 //fix (for L3 only): skip 'name' if it's present in the displayName, etc.. 640 if (editor.getProperty().equalsIgnoreCase("name") && bean instanceof Named) 641 { // the latter maybe not necessary... 642 Named named = (Named) bean; 643 if(value.equals(named.getDisplayName()) || value.equals(named.getStandardName())) 644 { 645 return; 646 } 647 } 648 649 if (editor.getProperty().equalsIgnoreCase("stepProcess") && bean instanceof BiochemicalPathwayStep) 650 { 651 BiochemicalPathwayStep bps = (BiochemicalPathwayStep) bean; 652 if(value.equals(bps.getStepConversion())) 653 { 654 return; 655 } 656 } 657 658 String prop = "bp:" + editor.getProperty(); 659 out.write(newline + " <" + prop); 660 661 if (value instanceof BioPAXElement) 662 { 663 String id = ((BioPAXElement) value).getRDFId(); 664 assert id != null; 665 if (!absoluteUris && base != null && id.startsWith(base)) 666 { 667 id = '#' + id.substring(base.length()); 668 } 669 out.write(" rdf:resource=\"" + id + "\" />"); 670 } else 671 { 672 String type = findLiteralType(editor); 673 String valString = StringEscapeUtils.escapeXml(value.toString()); 674 out.write(" rdf:datatype = \"" + xsd + type + "\">" + valString + 675 "</" + prop + ">"); 676 } 677 } 678 679 680 private String findLiteralType(PropertyEditor editor) 681 { 682 Class range = editor.getRange(); 683 String type = null; 684 if (range.isEnum() || range.equals(String.class)) 685 { 686 type = "string"; 687 } else if (range.equals(double.class) || range.equals(Double.class)) 688 { 689 type = "double"; 690 } else if (range.equals(int.class) || range.equals(Integer.class)) 691 { 692 type = "int"; 693 } else if (range.equals(float.class) || range.equals(Float.class)) 694 { 695 type = "float"; 696 } else if (range.equals(boolean.class) || range.equals(Boolean.class)) 697 { 698 type = "boolean"; 699 } else if (range.equals(long.class) || range.equals(Long.class)) 700 { 701 type = "long"; 702 } 703 return type; 704 } 705 706 707 private void writeIDLine(Writer out, BioPAXElement bpe, String name) throws IOException 708 { 709 710 out.write(newline + newline + "<" + name + " "); 711 String s = bpe.getRDFId(); 712 if (!absoluteUris && base != null && s.startsWith(base)) 713 { 714 String id = s.substring(base.length()); 715 out.write(RDF_ID + id + close); 716 } else 717 { 718 out.write(RDF_about + s + close); 719 } 720 721 722 } 723 724 725 private void initializeExporter(Model model) 726 { 727 base = model.getXmlBase(); 728 namespaces = new HashMap<String, String>(model.getNameSpacePrefixMap()); 729 730 normalizeNameSpaces(); // - for this reader/exporter tool 731 // also save the changes to the model? 732 if (normalizeNameSpaces) 733 { 734 model.getNameSpacePrefixMap().clear(); 735 model.getNameSpacePrefixMap().putAll(namespaces); 736 } 737 738 BioPAXLevel lev = model.getLevel(); 739 if (lev != this.level) resetLevel(lev, lev.getDefaultFactory()); 740 } 741 742 743 private void normalizeNameSpaces() 744 { 745 String owlPre = null; 746 String rdfPre = null; 747 String xsdPre = null; 748 749 for (String pre : namespaces.keySet()) 750 { 751 String ns = namespaces.get(pre); 752 if (rdfNS.equalsIgnoreCase(ns)) 753 { 754 rdfPre = pre; 755 } else if (owlNS.equalsIgnoreCase(ns)) 756 { 757 owlPre = pre; 758 } else if (xsdNS.equalsIgnoreCase(ns)) 759 { 760 xsdPre = pre; 761 } 762 } 763 764 if (owlPre != null) 765 { 766 namespaces.remove(owlPre); 767 } 768 769 if (rdfPre != null) 770 { 771 namespaces.remove(rdfPre); 772 } 773 774 if (xsdPre != null) 775 { 776 namespaces.remove(xsdPre); 777 } 778 779 namespaces.put("rdf", rdfNS); 780 namespaces.put("owl", owlNS); 781 namespaces.put("xsd", xsdNS); 782 } 783 784 785 private void writeHeader(Writer out) throws IOException 786 { 787 //Header 788 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 789 out.write(newline + "<rdf:RDF"); 790 String bpns = this.editorMap.getLevel().getNameSpace(); 791 for (String pre : namespaces.keySet()) 792 { 793 if (!pre.equals("bp")) 794 { 795 out.write(newline + " xmlns" + 796 (("".equals(pre)) ? "" : ":" + pre) + "=\"" + namespaces.get(pre) + "\""); 797 } 798 } 799 // write 'xmlns:bp' 800 out.write(newline + " xmlns:bp" + "=\"" + bpns + "\""); 801 802 if (base != null) 803 { 804 out.write(newline + " xml:base=\"" + base + "\""); 805 } 806 807 out.write(">"); 808 out.write(newline + "<owl:Ontology rdf:about=\"\">"); 809 out.write(newline + " <owl:imports rdf:resource=\"" + bpns + "\" />"); 810 out.write(newline + "</owl:Ontology>"); 811 } 812 813 814 /** 815 * Sets the flag used when exporting a BioPAX model to RDF/XML: 816 * true - to always write full URI in rdf:resource and use 817 * rdf:about instead rdf:ID (does not matter xml:base is set or not). 818 * This is good for the data loading a RDF/SPARQL servers, such as Virtuoso, 819 * so they generate correct and resolvable links from BioPAX URIs 820 * (use of rdf:ID="localId" and rdf:resource="#localID" is known to make 821 * them insert extra '#' between xml:base and localId). 822 * 823 * @param absoluteUris true/false - whether to force writing absolute URIs (thus, never use rdf:ID) 824 */ 825 public void absoluteUris(boolean absoluteUris) { 826 this.absoluteUris = absoluteUris; 827 } 828 829 /** 830 * @see #absoluteUris(boolean) 831 * @return true/false 832 */ 833 public boolean isAbsoluteUris() 834 { 835 return this.absoluteUris; 836 } 837 838 839 /** 840 * Sets the flag used when exporting a BioPAX model to RDF/XML: 841 * true - to clean up current namespaces (e.g., those read from a file) 842 * and use defaults instead (prefixes: 'rdf', 'rdfs', 'owl', 'xsd') 843 * @param normalizeNameSpaces true/false 844 */ 845 public void normalizeNameSpaces(boolean normalizeNameSpaces) 846 { 847 this.normalizeNameSpaces = normalizeNameSpaces; 848 } 849 850 /** 851 * @see #normalizeNameSpaces() 852 * @return true/false 853 */ 854 public boolean isNormalizeNameSpaces() 855 { 856 return this.normalizeNameSpaces; 857 } 858 859 /** 860 * @see #mergeDuplicates(boolean) 861 * @return true/false 862 */ 863 public boolean isMergeDuplicates() 864 { 865 return this.mergeDuplicates; 866 } 867 868 869 /** 870 * Serializes a (not too large) BioPAX model to the RDF/XML (OWL) formatted string. 871 * 872 * @param model a BioPAX object model to convert to the RDF/XML format 873 * @return the BioPAX data in the RDF/XML format 874 * @throws IllegalArgumentException if model is null 875 * @throws OutOfMemoryError when it cannot be stored in a byte array (max 2Gb). 876 */ 877 public static String convertToOwl(Model model) 878 { 879 if (model == null) throw new IllegalArgumentException(); 880 881 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 882 883 (new SimpleIOHandler(model.getLevel())).convertToOWL(model, outputStream); 884 885 try 886 { 887 return outputStream.toString("UTF-8"); 888 } 889 catch (UnsupportedEncodingException e) 890 { 891 log.error(e); 892 return outputStream.toString(); 893 } 894 } 895 896} 897