package net.enilink.komma.rdf4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.rdf4j.model.BNode;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.Dataset;
import org.eclipse.rdf4j.query.impl.MapBindingSet;
import org.eclipse.rdf4j.query.impl.SimpleDataset;
import com.google.inject.Inject;
import net.enilink.komma.core.BlankNode;
import net.enilink.komma.core.IBindings;
import net.enilink.komma.core.ILiteral;
import net.enilink.komma.core.IReference;
import net.enilink.komma.core.IReferenceable;
import net.enilink.komma.core.IStatement;
import net.enilink.komma.core.IValue;
import net.enilink.komma.core.KommaException;
import net.enilink.komma.core.URI;
import net.enilink.komma.internal.rdf4j.RDF4JLiteral;
import net.enilink.komma.internal.rdf4j.RDF4JReference;
public class RDF4JValueConverter {
private static final IRI[] EMPTY_IRIS = {};
private static final IRI[] NULL_IRI = { null };
protected ValueFactory valueFactory;
protected final Map<String, BNode> bnodeMap = new HashMap<>();
@Inject
public RDF4JValueConverter(ValueFactory valueFactory) {
this.valueFactory = valueFactory;
}
public Dataset createDataset(IReference[] readContexts,
IReference[] modifyContexts) {
SimpleDataset ds = new SimpleDataset();
for (IRI graph : toRdf4jIRI(readContexts)) {
ds.addDefaultGraph(graph);
if (graph != null) {
ds.addNamedGraph(graph);
}
}
IRI[] rdf4jContexts = toRdf4jIRI(modifyContexts);
for (IRI graph : rdf4jContexts) {
ds.addDefaultRemoveGraph(graph);
}
if (rdf4jContexts.length > 0) {
ds.setDefaultInsertGraph(rdf4jContexts[0]);
}
return ds;
}
public IReference fromRdf4j(Resource resource) {
return (IReference) fromRdf4j((Value) resource);
}
public IValue fromRdf4j(Value value) {
if (value == null) {
return null;
}
if (value instanceof Resource) {
return new RDF4JReference((Resource) value);
}
return new RDF4JLiteral((Literal) value);
}
public BindingSet toRdf4j(IBindings<?> bindings) {
MapBindingSet bindingSet = new MapBindingSet();
for (String key : bindings.getKeys()) {
bindingSet.addBinding(key, toRdf4j((IValue) bindings.get(key)));
}
return bindingSet;
}
public Statement toRdf4j(IStatement next) {
return valueFactory.createStatement((Resource) toRdf4j(next.getSubject()),
toRdf4j(next.getPredicate().getURI()),
toRdf4j((IValue) next.getObject()),
toRdf4j(next.getContext()));
}
public Resource toRdf4j(IReference reference) {
if (reference == null) {
return null;
}
if (reference instanceof IReferenceable) {
reference = ((IReferenceable) reference).getReference();
}
if (reference instanceof RDF4JReference) {
Resource resource = ((RDF4JReference) reference)
.getRDF4JResource();
if (resource instanceof BNode
&& ((BNode) resource).getID().startsWith("new-")) {
// enforce that newly created RDF4J blank nodes are also
// correctly converted
reference = new BlankNode(reference.toString());
} else {
return resource;
}
}
URI uri = reference.getURI();
if (uri != null) {
return toRdf4j(reference.getURI());
} else {
String valueAsString = reference.toString();
if (valueAsString.startsWith("_:")) {
String id = valueAsString.substring(2);
if (id.startsWith("new-")) {
// convert newly created blank nodes with magic prefix
// "new-"
synchronized (bnodeMap) {
BNode bnode = bnodeMap.get(id);
if (bnode == null) {
bnode = valueFactory.createBNode();
bnodeMap.put(id, bnode);
}
return bnode;
}
}
return valueFactory.createBNode(id);
}
throw new KommaException(
"Cannot convert blank node with nominal value '"
+ valueAsString + "' to RDF4J blank node.");
}
}
public Value toRdf4j(IValue value) {
if (value == null) {
return null;
}
if (value instanceof IReference) {
return toRdf4j((IReference) value);
}
if (value instanceof ILiteral) {
if (value instanceof RDF4JLiteral) {
return ((RDF4JLiteral) value).getRDF4JLiteral();
}
ILiteral literal = (ILiteral) value;
String language = literal.getLanguage();
if (language != null) {
return valueFactory.createLiteral(literal.getLabel(), language);
} else {
return valueFactory
.createLiteral(literal.getLabel(),
(IRI) toRdf4j(literal
.getDatatype()));
}
}
throw new KommaException("Cannot convert object of type: "
+ value.getClass().getName());
}
public IRI toRdf4j(URI uri) {
if (uri == null) {
return null;
}
// FIXME: check if simply replacing URI w/ IRI is appropriate
return valueFactory.createIRI(uri.toString());
}
public IRI[] toRdf4jIRI(IReference... references) {
if (references.length == 0) {
return EMPTY_IRIS;
} else if (references.length == 1 && references[0] == null) {
return NULL_IRI;
}
List<IRI> iris = new ArrayList<IRI>(
references.length);
for (IReference ref : references) {
if (ref == null) {
iris.add(null);
} else {
Resource resource = toRdf4j(ref);
if (resource instanceof IRI) {
iris.add((IRI) resource);
}
}
}
return iris.toArray(new IRI[iris.size()]);
}
public void reset() {
synchronized (bnodeMap) {
bnodeMap.clear();
}
}
}