001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.commons.rdf.rdf4j; 019 020import java.util.Arrays; 021import java.util.EnumSet; 022import java.util.Objects; 023import java.util.Set; 024import java.util.UUID; 025 026// To avoid confusion, avoid importing 027// classes that are in both 028// commons.rdf and openrdf.model (e.g. IRI, Literal) 029import org.apache.commons.rdf.api.BlankNode; 030import org.apache.commons.rdf.api.BlankNodeOrIRI; 031import org.apache.commons.rdf.api.Dataset; 032import org.apache.commons.rdf.api.Graph; 033import org.apache.commons.rdf.api.Quad; 034import org.apache.commons.rdf.api.RDFTerm; 035import org.apache.commons.rdf.api.RDF; 036import org.apache.commons.rdf.api.Triple; 037import org.apache.commons.rdf.api.TripleLike; 038import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory; 039import org.eclipse.rdf4j.model.BNode; 040import org.eclipse.rdf4j.model.IRI; 041import org.eclipse.rdf4j.model.Literal; 042import org.eclipse.rdf4j.model.Model; 043import org.eclipse.rdf4j.model.Resource; 044import org.eclipse.rdf4j.model.Statement; 045import org.eclipse.rdf4j.model.Value; 046import org.eclipse.rdf4j.model.ValueFactory; 047import org.eclipse.rdf4j.model.impl.LinkedHashModel; 048import org.eclipse.rdf4j.model.impl.SimpleValueFactory; 049import org.eclipse.rdf4j.repository.Repository; 050import org.eclipse.rdf4j.repository.RepositoryConnection; 051import org.eclipse.rdf4j.repository.sail.SailRepository; 052import org.eclipse.rdf4j.sail.Sail; 053import org.eclipse.rdf4j.sail.memory.MemoryStore; 054 055/** 056 * RDF4J implementation of RDF. 057 * <p> 058 * The {@link #RDF4J()} constructor uses a {@link SimpleValueFactory} to create 059 * corresponding RDF4J {@link Value} instances. Alternatively, this factory can 060 * be constructed with a different {@link ValueFactory} using 061 * {@link #RDF4J(ValueFactory)}. 062 * <p> 063 * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to 064 * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are 065 * converted with the same {@link RDF4J} instance and have the same 066 * {@link BNode#getID()}. 067 * <p> 068 * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}. 069 * To use other models, see {@link #asGraph(Model)}. 070 * <p> 071 * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph}, 072 * use {@link #asDataset(Repository, Option...)} or 073 * {@link #asGraph(Repository, Option...)}. 074 * <p> 075 * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement} 076 * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to 077 * convert a {@link Quad}. 078 * <p> 079 * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement}, 080 * use {@link #asStatement(TripleLike)}. This recognises previously converted 081 * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their 082 * {@link RDF4JTripleLike#asStatement()}. 083 * <p> 084 * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF 085 * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises 086 * previously converted {@link RDF4JTerm}s without re-converting their 087 * {@link RDF4JTerm#asValue()}. 088 * <p> 089 * For the purpose of {@link BlankNode} equivalence, this factory contains an 090 * internal {@link UUID} salt that is used by adapter methods like 091 * {@link #asQuad(Statement)}, {@link #asTriple(Statement)}, 092 * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As 093 * RDF4J {@link BNode} instances from multiple repositories or models may have 094 * the same {@link BNode#getID()}, converting them with the above methods might 095 * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph} 096 * and {@link Dataset} adapter methods like 097 * {@link #asDataset(Repository, Option...)} and 098 * {@link #asGraph(Repository, Option...)} therefore uses a unique {@link RDF4J} 099 * internally. 100 * 101 * @see RDF 102 * 103 */ 104public final class RDF4J implements RDF { 105 106 /** 107 * InternalRDF4JFactory is deliberately abstract 108 */ 109 private static InternalRDF4JFactory rdf4j = new InternalRDF4JFactory() { 110 }; 111 112 public enum Option { 113 /** 114 * The Graph/Dataset should include any inferred statements 115 */ 116 includeInferred, 117 /** 118 * The graph/dataset should handle {@link Repository#initialize()} (if 119 * needed) and {@link Repository#shutDown()} on {@link Graph#close()} / 120 * {@link Dataset#close()}. 121 */ 122 handleInitAndShutdown 123 } 124 125 private final UUID salt; 126 127 private final ValueFactory valueFactory; 128 129 /** 130 * Construct an {@link RDF4J}. 131 * 132 */ 133 public RDF4J() { 134 this(SimpleValueFactory.getInstance(), UUID.randomUUID()); 135 } 136 137 /** 138 * Construct an {@link RDF4J}. 139 * <p> 140 * This constructor is intended for use with the value factory from 141 * {@link Repository#getValueFactory()} when using Repository-based graphs 142 * and datasets. 143 * 144 * @param valueFactory 145 * The RDF4J {@link ValueFactory} to use 146 */ 147 public RDF4J(final ValueFactory valueFactory) { 148 this(valueFactory, UUID.randomUUID()); 149 } 150 151 /** 152 * Construct an {@link RDF4J}. 153 * <p> 154 * This constructor may be used if reproducible 155 * {@link BlankNode#uniqueReference()} in {@link BlankNode} is desirable. 156 * 157 * @param salt 158 * An {@link UUID} salt to be used by any created 159 * {@link BlankNode}s for the purpose of 160 * {@link BlankNode#uniqueReference()} 161 */ 162 public RDF4J(final UUID salt) { 163 this(SimpleValueFactory.getInstance(), salt); 164 } 165 166 /** 167 * Construct an {@link RDF4J}. 168 * <p> 169 * This constructor may be used if reproducible 170 * {@link BlankNode#uniqueReference()} in {@link BlankNode} is desirable. 171 * 172 * @param valueFactory 173 * The RDF4J {@link ValueFactory} to use 174 * @param salt 175 * An {@link UUID} salt to be used by any created 176 * {@link BlankNode}s for the purpose of 177 * {@link BlankNode#uniqueReference()} 178 */ 179 public RDF4J(final ValueFactory valueFactory, final UUID salt) { 180 this.valueFactory = valueFactory; 181 this.salt = salt; 182 } 183 184 /** 185 * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}. 186 * <p> 187 * For the purpose of {@link BlankNode} equivalence, this method will use an 188 * internal salt UUID that is unique per instance of {@link RDF4J}. 189 * <p> 190 * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s multiple 191 * repositories or models, then their {@link BNode}s may have the same 192 * {@link BNode#getID()}, which with this method would become equivalent 193 * according to {@link BlankNode#equals(Object)} and 194 * {@link BlankNode#uniqueReference()}, unless a separate {@link RDF4J} 195 * instance is used per RDF4J repository/model. 196 * 197 * @param statement 198 * The statement to convert 199 * @return A {@link RDF4JQuad} that is equivalent to the statement 200 */ 201 public RDF4JQuad asQuad(final Statement statement) { 202 return rdf4j.createQuadImpl(statement, salt); 203 } 204 205 /** 206 * 207 * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}. 208 * <p> 209 * The value will be of the same kind as the term, e.g. a 210 * {@link org.eclipse.rdf4j.model.BNode} is converted to a 211 * {@link org.apache.commons.rdf.api.BlankNode}, a 212 * {@link org.eclipse.rdf4j.model.IRI} is converted to a 213 * {@link org.apache.commons.rdf.api.IRI} and a 214 * {@link org.eclipse.rdf4j.model.Literal}. is converted to a 215 * {@link org.apache.commons.rdf.api.Literal} 216 * <p> 217 * For the purpose of {@link BlankNode} equivalence, this method will use an 218 * internal salt UUID that is unique per instance of {@link RDF4J}. 219 * <p> 220 * <strong>NOTE:</strong> If combining RDF4J values from multiple 221 * repositories or models, then their {@link BNode}s may have the same 222 * {@link BNode#getID()}, which with this method would become equivalent 223 * according to {@link BlankNode#equals(Object)} and 224 * {@link BlankNode#uniqueReference()}, unless a separate {@link RDF4J} 225 * instance is used per RDF4J repository/model. 226 * 227 * @param value 228 * The RDF4J {@link Value} to convert. 229 * @return A {@link RDFTerm} that corresponds to the RDF4J value 230 * @throws IllegalArgumentException 231 * if the value is not a BNode, Literal or IRI 232 */ 233 public RDF4JTerm asRDFTerm(final Value value) { 234 return asRDFTerm(value, salt); 235 } 236 237 /** 238 * 239 * Adapt a RDF4J 240 * {@link org.eclipse.rdf4j.model.BNode} as a Commons RDF 241 * {@link org.apache.commons.rdf.api.BlankNode} 242 * <p> 243 * For the purpose of {@link BlankNode} equivalence, this method will use an 244 * internal salt UUID that is unique per instance of {@link RDF4J}. 245 * <p> 246 * <strong>NOTE:</strong> If combining RDF4J values from multiple 247 * repositories or models, then their {@link BNode}s may have the same 248 * {@link BNode#getID()}, which with this method would become equivalent 249 * according to {@link BlankNode#equals(Object)} and 250 * {@link BlankNode#uniqueReference()}, unless a separate {@link RDF4J} 251 * instance is used per RDF4J repository/model. 252 * 253 * @param value 254 * The RDF4J {@link BNode} to convert. 255 * @return A {@link RDF4JBlankNode} that corresponds to the RDF4J BNode 256 */ 257 public RDF4JBlankNode asRDFTerm(final BNode value) { 258 return rdf4j.createBlankNodeImpl(value, salt); 259 } 260 261 /** 262 * 263 * Adapt a RDF4J 264 * {@link org.eclipse.rdf4j.model.Literal} as a Commons RDF 265 * {@link org.apache.commons.rdf.api.Literal} 266 * <p> 267 * @param value 268 * The RDF4J {@link Literal} to convert. 269 * @return A {@link RDF4JLiteral} that corresponds to the RDF4J literal 270 */ 271 public RDF4JLiteral asRDFTerm(final Literal value) { 272 return rdf4j.createLiteralImpl(value); 273 } 274 275 /** 276 * 277 * Adapt a RDF4J 278 * {@link org.eclipse.rdf4j.model.IRI} as a Commons RDF 279 * {@link org.apache.commons.rdf.api.IRI} 280 * <p> 281 * @param value 282 * The RDF4J {@link Value} to convert. 283 * @return A {@link RDF4JIRI} that corresponds to the RDF4J IRI 284 */ 285 public RDF4JIRI asRDFTerm(final org.eclipse.rdf4j.model.IRI value) { 286 return rdf4j.createIRIImpl(value); 287 } 288 289 /** 290 * 291 * Adapt a RDF4J 292 * {@link org.eclipse.rdf4j.model.Resource} as a Commons RDF 293 * {@link org.apache.commons.rdf.api.BlankNodeOrIRI} 294 * <p> 295 * @param value 296 * The RDF4J {@link Value} to convert. 297 * @return A {@link RDF4JBlankNodeOrIRI} that corresponds to the RDF4J Resource 298 */ 299 public RDF4JBlankNodeOrIRI asRDFTerm(final org.eclipse.rdf4j.model.Resource value) { 300 if(value instanceof IRI){ 301 return asRDFTerm((IRI)value); 302 } else if (value instanceof BNode){ 303 return asRDFTerm((BNode)value); 304 } 305 throw new IllegalArgumentException("Value is not a BNode or IRI: " + value.getClass()); 306 } 307 308 /** 309 * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}. 310 * <p> 311 * The value will be of the same kind as the term, e.g. a 312 * {@link org.eclipse.rdf4j.model.BNode} is converted to a 313 * {@link org.apache.commons.rdf.api.BlankNode}, a 314 * {@link org.eclipse.rdf4j.model.IRI} is converted to a 315 * {@link org.apache.commons.rdf.api.IRI} and a 316 * {@link org.eclipse.rdf4j.model.Literal}. is converted to a 317 * {@link org.apache.commons.rdf.api.Literal} 318 * 319 * @param value 320 * The RDF4J {@link Value} to convert. 321 * @param salt 322 * A {@link UUID} salt to use for uniquely mapping any 323 * {@link BNode}s. The salt should typically be the same for 324 * multiple statements in the same {@link Repository} or 325 * {@link Model} to ensure {@link BlankNode#equals(Object)} and 326 * {@link BlankNode#uniqueReference()} works as intended. 327 * @return A {@link RDFTerm} that corresponds to the RDF4J value 328 * @throws IllegalArgumentException 329 * if the value is not a BNode, Literal or IRI 330 */ 331 public static RDF4JTerm asRDFTerm(final Value value, final UUID salt) { 332 if (value instanceof BNode) { 333 return rdf4j.createBlankNodeImpl((BNode) value, salt); 334 } 335 if (value instanceof org.eclipse.rdf4j.model.Literal) { 336 return rdf4j.createLiteralImpl((org.eclipse.rdf4j.model.Literal) value); 337 } 338 if (value instanceof org.eclipse.rdf4j.model.IRI) { 339 return rdf4j.createIRIImpl((org.eclipse.rdf4j.model.IRI) value); 340 } 341 throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass()); 342 } 343 344 /** 345 * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}. 346 * <p> 347 * Changes to the dataset are reflected in the repository, and vice versa. 348 * <p> 349 * <strong>Note:</strong> Some operations on the {@link RDF4JDataset} 350 * requires the use of try-with-resources to close underlying 351 * {@link RepositoryConnection}s, including {@link RDF4JDataset#iterate()}, 352 * {@link RDF4JDataset#stream()} and {@link RDF4JDataset#getGraphNames()}. 353 * 354 * @param repository 355 * RDF4J {@link Repository} to connect to. 356 * @param options 357 * Zero or more {@link Option} 358 * @return A {@link Dataset} backed by the RDF4J repository. 359 */ 360 public RDF4JDataset asDataset(final Repository repository, final Option... options) { 361 final EnumSet<Option> opts = optionSet(options); 362 return rdf4j.createRepositoryDatasetImpl(repository, opts.contains(Option.handleInitAndShutdown), 363 opts.contains(Option.includeInferred)); 364 } 365 366 /** 367 * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}. 368 * <p> 369 * Changes to the graph are reflected in the model, and vice versa. 370 * 371 * @param model 372 * RDF4J {@link Model} to adapt. 373 * @return Adapted {@link Graph}. 374 */ 375 public RDF4JGraph asGraph(final Model model) { 376 return rdf4j.createModelGraphImpl(model, this); 377 } 378 379 /** 380 * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}. 381 * <p> 382 * The graph will only include triples in the default graph (equivalent to 383 * context <code>new Resource[0]{null})</code> in RDF4J). 384 * <p> 385 * Changes to the graph are reflected in the repository, and vice versa. 386 * <p> 387 * <strong>Note:</strong> Some operations on the {@link RDF4JGraph} requires 388 * the use of try-with-resources to close underlying 389 * {@link RepositoryConnection}s, including {@link RDF4JGraph#iterate()} and 390 * {@link RDF4JGraph#stream()}. 391 * 392 * @param repository 393 * RDF4J {@link Repository} to connect to. 394 * @param options 395 * Zero or more {@link Option} 396 * @return A {@link Graph} backed by the RDF4J repository. 397 */ 398 public RDF4JGraph asGraph(final Repository repository, final Option... options) { 399 final EnumSet<Option> opts = optionSet(options); 400 return rdf4j.createRepositoryGraphImpl(repository, opts.contains(Option.handleInitAndShutdown), 401 opts.contains(Option.includeInferred), new Resource[] { null }); // default 402 // graph 403 } 404 405 /** 406 * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}. 407 * <p> 408 * The graph will include triples in any contexts (e.g. the union graph). 409 * <p> 410 * Changes to the graph are reflected in the repository, and vice versa. 411 * 412 * @param repository 413 * RDF4J {@link Repository} to connect to. 414 * @param options 415 * Zero or more {@link Option} 416 * @return A union {@link Graph} backed by the RDF4J repository. 417 */ 418 public RDF4JGraph asGraphUnion(final Repository repository, final Option... options) { 419 final EnumSet<Option> opts = optionSet(options); 420 return rdf4j.createRepositoryGraphImpl(repository, opts.contains(Option.handleInitAndShutdown), 421 opts.contains(Option.includeInferred), new Resource[] {}); // union 422 // graph 423 424 } 425 426 /** 427 * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}. 428 * <p> 429 * The graph will include triples in the specified contexts. 430 * <p> 431 * Changes to the graph are reflected in the repository, and vice versa. 432 * Triples added/removed to the graph are reflected in all the specified 433 * contexts. 434 * <p> 435 * <strong>Note:</strong> Some operations on the {@link RDF4JGraph} requires 436 * the use of try-with-resources to close underlying 437 * {@link RepositoryConnection}s, including {@link RDF4JGraph#iterate()} and 438 * {@link RDF4JGraph#stream()}. 439 * 440 * @param repository 441 * RDF4J {@link Repository} to connect to. 442 * @param contexts 443 * A {@link Set} of {@link BlankNodeOrIRI} specifying the graph 444 * names to use as a context. The set may include the value 445 * <code>null</code> to indicate the default graph. The empty set 446 * indicates any context, e.g. the <em>union graph</em>. 447 * @param option 448 * Zero or more {@link Option}s 449 * @return A {@link Graph} backed by the RDF4J repository. 450 */ 451 public RDF4JGraph asGraph(final Repository repository, final Set<? extends BlankNodeOrIRI> contexts, final Option... option) { 452 final EnumSet<Option> opts = optionSet(option); 453 /** NOTE: asValue() deliberately CAN handle <code>null</code> */ 454 final Resource[] resources = contexts.stream().map(g -> (Resource) asValue(g)).toArray(Resource[]::new); 455 return rdf4j.createRepositoryGraphImpl(Objects.requireNonNull(repository), 456 opts.contains(Option.handleInitAndShutdown), opts.contains(Option.includeInferred), resources); 457 } 458 459 /** 460 * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J 461 * {@link Statement}. 462 * <p> 463 * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or a 464 * {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is 465 * returned as-is. Note that this means that a {@link RDF4JTriple} would 466 * preserve its {@link Statement#getContext()}, and that any 467 * {@link BlankNode}s would be deemed equivalent in RDF4J if they have the 468 * same {@link BNode#getID()}. 469 * 470 * @param tripleLike 471 * A {@link Triple} or {@link Quad} to adapt 472 * @return A corresponding {@link Statement} 473 */ 474 public Statement asStatement(final TripleLike tripleLike) { 475 if (tripleLike instanceof RDF4JTripleLike) { 476 // Return original statement - this covers both RDF4JQuad and 477 // RDF4JTriple 478 return ((RDF4JTripleLike) tripleLike).asStatement(); 479 } 480 481 final org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject()); 482 final org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate()); 483 final Value object = asValue(tripleLike.getObject()); 484 485 org.eclipse.rdf4j.model.Resource context = null; 486 if (tripleLike instanceof Quad) { 487 final Quad quad = (Quad) tripleLike; 488 context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null)); 489 } 490 491 return getValueFactory().createStatement(subject, predicate, object, context); 492 } 493 494 /** 495 * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}. 496 * <p> 497 * For the purpose of {@link BlankNode} equivalence, this method will use an 498 * internal salt UUID that is unique per instance of {@link RDF4J}. 499 * <p> 500 * <strong>NOTE:</strong> If combining RDF4J statements from multiple 501 * repositories or models, then their {@link BNode}s may have the same 502 * {@link BNode#getID()}, which with this method would become equivalent 503 * according to {@link BlankNode#equals(Object)} and 504 * {@link BlankNode#uniqueReference()}, unless a separate {@link RDF4J} 505 * instance is used per RDF4J repository/model. 506 * 507 * @param statement 508 * The RDF4J {@link Statement} to adapt. 509 * @return A {@link RDF4JTriple} that is equivalent to the statement 510 */ 511 public RDF4JTriple asTriple(final Statement statement) { 512 return rdf4j.createTripleImpl(statement, salt); 513 } 514 515 /** 516 * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}. 517 * <p> 518 * The value will be of the same kind as the term, e.g. a 519 * {@link org.apache.commons.rdf.api.BlankNode} is converted to a 520 * {@link org.eclipse.rdf4j.model.BNode}, a 521 * {@link org.apache.commons.rdf.api.IRI} is converted to a 522 * {@link org.eclipse.rdf4j.model.IRI} and a 523 * {@link org.apache.commons.rdf.api.Literal} is converted to a 524 * {@link org.eclipse.rdf4j.model.Literal}. 525 * <p> 526 * If the provided {@link RDFTerm} is <code>null</code>, then the returned 527 * value is <code>null</code>. 528 * <p> 529 * If the provided term is an instance of {@link RDF4JTerm}, then the 530 * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that 531 * this could mean that a {@link Value} from a different kind of 532 * {@link ValueFactory} could be returned. 533 * 534 * @param term 535 * RDFTerm to adapt to RDF4J Value 536 * @return Adapted RDF4J {@link Value} 537 */ 538 public Value asValue(final RDFTerm term) { 539 if (term == null) { 540 return null; 541 } 542 if (term instanceof RDF4JTerm) { 543 // One of our own - avoid converting again. 544 // (This is crucial to avoid double-escaping in BlankNode) 545 return ((RDF4JTerm) term).asValue(); 546 } 547 if (term instanceof org.apache.commons.rdf.api.IRI) { 548 final org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) term; 549 return getValueFactory().createIRI(iri.getIRIString()); 550 } 551 if (term instanceof org.apache.commons.rdf.api.Literal) { 552 final org.apache.commons.rdf.api.Literal literal = (org.apache.commons.rdf.api.Literal) term; 553 final String label = literal.getLexicalForm(); 554 if (literal.getLanguageTag().isPresent()) { 555 final String lang = literal.getLanguageTag().get(); 556 return getValueFactory().createLiteral(label, lang); 557 } 558 final org.eclipse.rdf4j.model.IRI dataType = (org.eclipse.rdf4j.model.IRI) asValue(literal.getDatatype()); 559 return getValueFactory().createLiteral(label, dataType); 560 } 561 if (term instanceof BlankNode) { 562 // This is where it gets tricky to support round trips! 563 final BlankNode blankNode = (BlankNode) term; 564 // FIXME: The uniqueReference might not be a valid BlankNode 565 // identifier.. 566 // does it have to be in RDF4J? 567 return getValueFactory().createBNode(blankNode.uniqueReference()); 568 } 569 throw new IllegalArgumentException("RDFTerm was not an IRI, Literal or BlankNode: " + term.getClass()); 570 } 571 572 @Override 573 public RDF4JBlankNode createBlankNode() { 574 final BNode bnode = getValueFactory().createBNode(); 575 return asRDFTerm(bnode); 576 } 577 578 @Override 579 public RDF4JBlankNode createBlankNode(final String name) { 580 final BNode bnode = getValueFactory().createBNode(name); 581 return asRDFTerm(bnode); 582 } 583 584 /** 585 * {@inheritDoc} 586 * <p> 587 * <strong>Note:</strong> Some operations on the {@link RDF4JDataset} 588 * requires the use of try-with-resources to close underlying 589 * {@link RepositoryConnection}s, including {@link RDF4JDataset#iterate()}, 590 * {@link RDF4JDataset#stream()} and {@link RDF4JDataset#getGraphNames()}. 591 * 592 */ 593 @Override 594 public RDF4JDataset createDataset() { 595 final Sail sail = new MemoryStore(); 596 final Repository repository = new SailRepository(sail); 597 return rdf4j.createRepositoryDatasetImpl(repository, true, false); 598 } 599 600 @Override 601 public RDF4JGraph createGraph() { 602 return asGraph(new LinkedHashModel()); 603 } 604 605 @Override 606 public RDF4JIRI createIRI(final String iri) throws IllegalArgumentException { 607 return asRDFTerm(getValueFactory().createIRI(iri)); 608 } 609 610 @Override 611 public RDF4JLiteral createLiteral(final String lexicalForm) throws IllegalArgumentException { 612 final org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm); 613 return asRDFTerm(lit); 614 } 615 616 @Override 617 public org.apache.commons.rdf.api.Literal createLiteral(final String lexicalForm, final org.apache.commons.rdf.api.IRI dataType) 618 throws IllegalArgumentException { 619 final org.eclipse.rdf4j.model.IRI iri = getValueFactory().createIRI(dataType.getIRIString()); 620 final org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm, iri); 621 return asRDFTerm(lit); 622 } 623 624 @Override 625 public org.apache.commons.rdf.api.Literal createLiteral(final String lexicalForm, final String languageTag) 626 throws IllegalArgumentException { 627 final org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm, languageTag); 628 return asRDFTerm(lit); 629 } 630 631 @Override 632 public RDF4JTriple createTriple(final BlankNodeOrIRI subject, final org.apache.commons.rdf.api.IRI predicate, final RDFTerm object) 633 throws IllegalArgumentException { 634 final Statement statement = getValueFactory().createStatement( 635 (org.eclipse.rdf4j.model.Resource) asValue(subject), (org.eclipse.rdf4j.model.IRI) asValue(predicate), 636 asValue(object)); 637 return asTriple(statement); 638 } 639 640 @Override 641 public Quad createQuad(final BlankNodeOrIRI graphName, final BlankNodeOrIRI subject, final org.apache.commons.rdf.api.IRI predicate, 642 final RDFTerm object) throws IllegalArgumentException { 643 final Statement statement = getValueFactory().createStatement( 644 (org.eclipse.rdf4j.model.Resource) asValue(subject), (org.eclipse.rdf4j.model.IRI) asValue(predicate), 645 asValue(object), (org.eclipse.rdf4j.model.Resource) asValue(graphName)); 646 return asQuad(statement); 647 } 648 649 public ValueFactory getValueFactory() { 650 return valueFactory; 651 } 652 653 private EnumSet<Option> optionSet(final Option... options) { 654 final EnumSet<Option> opts = EnumSet.noneOf(Option.class); 655 opts.addAll(Arrays.asList(options)); 656 return opts; 657 } 658 659}