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