package edu.isi.karma.kr2rml.writer;
import java.io.PrintWriter;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import edu.isi.karma.kr2rml.PredicateObjectMap;
import edu.isi.karma.kr2rml.Prefix;
import edu.isi.karma.kr2rml.ShortHandURIGenerator;
public abstract class SFKR2RMLRDFWriter<E> extends KR2RMLRDFWriter {
protected boolean disableNesting = false;
protected boolean firstObject = true;
protected ConcurrentHashMap<String, ConcurrentHashMap<String, E>> generatedObjectsByTriplesMapId;
protected ConcurrentHashMap<String, E> generatedObjectsWithoutTriplesMap;
protected ConcurrentHashMap<String, ConcurrentHashMap<String, E>> rootObjectsByTriplesMapId = new ConcurrentHashMap<>();
protected ShortHandURIGenerator shortHandURIGenerator = new ShortHandURIGenerator();
protected String rootTriplesMapId;
protected Set<String> rootTriplesMapIds;
protected String baseURI = "";
private static Set<String> numericLiteralTypes = new HashSet<>();
static {
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#decimal");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#integer");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#nonPositiveInteger");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#negativeInteger");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#long");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#int");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#short");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#byte");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#nonNegativeInteger");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#unsignedLong");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#unsignedInt");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#unsignedShort");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#unsignedInt");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#unsignedByte");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#positiveInteger");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#float");
numericLiteralTypes.add("http://www.w3.org/2001/XMLSchema#double");
}
public SFKR2RMLRDFWriter (PrintWriter outWriter) {
this.outWriter = outWriter;
generatedObjectsWithoutTriplesMap = new ConcurrentHashMap<>();
generatedObjectsByTriplesMapId = new ConcurrentHashMap<>();
rootTriplesMapIds = new HashSet<>();
this.rootObjectsByTriplesMapId.put("", new ConcurrentHashMap<String, E>());
initializeOutput();
}
public SFKR2RMLRDFWriter (PrintWriter outWriter, String baseURI) {
this(outWriter);
if (baseURI != null)
this.baseURI = baseURI;
}
public SFKR2RMLRDFWriter (PrintWriter outWriter, String baseURI, boolean disableNesting) {
this(outWriter, baseURI);
this.disableNesting = disableNesting;
}
protected abstract void initializeOutput();
@Override
public void outputTripleWithURIObject(String subjUri, String predicateUri,
String objectUri) {
E subject = checkAndAddsubjUri(null, generatedObjectsWithoutTriplesMap, subjUri);
E object = getGeneratedObject(generatedObjectsWithoutTriplesMap, objectUri);
addValue(null, subject, predicateUri, object !=null? object : objectUri);
if(!disableNesting)
{
rootObjectsByTriplesMapId.get("").remove(objectUri);
}
}
@Override
public void outputTripleWithLiteralObject(String subjUri,
String predicateUri, String value, String literalType, String language) {
E subject = checkAndAddsubjUri(null, generatedObjectsWithoutTriplesMap, subjUri);
addValue(null, subject, predicateUri, convertLiteral(value, literalType, language));
}
@Override
public void outputQuadWithLiteralObject(String subjUri,
String predicateUri, String value, String literalType, String language, String graph) {
outputTripleWithLiteralObject(subjUri, predicateUri, value, literalType, language);
}
protected E checkAndAddSubjUri(String triplesMapId, String subjUri)
{
ConcurrentHashMap<String, E> generatedObjects = generatedObjectsByTriplesMapId.get(triplesMapId);
if(null == generatedObjects)
{
generatedObjectsByTriplesMapId.putIfAbsent(triplesMapId, new ConcurrentHashMap<String, E>());
generatedObjects = generatedObjectsByTriplesMapId.get(triplesMapId);
}
return checkAndAddsubjUri(triplesMapId, generatedObjects, subjUri);
}
protected E checkAndAddsubjUri(String triplesMapId, ConcurrentHashMap<String, E> generatedObjects, String subjUri) {
if (!generatedObjects.containsKey(subjUri)) {
E object = getNewObject(triplesMapId, subjUri);
generatedObjects.putIfAbsent(subjUri, object);
object = generatedObjects.get(subjUri);
if(triplesMapId == null || rootTriplesMapIds.isEmpty() || rootTriplesMapIds.contains(triplesMapId))
{
rootObjectsByTriplesMapId.get(triplesMapId).put(subjUri, object);
}
else if (disableNesting)
{
rootObjectsByTriplesMapId.get("").put(subjUri, object);
}
return object;
}
return generatedObjects.get(subjUri);
}
private void addURIObject(PredicateObjectMap pom, String subjUri, String predicateUri, String objectUri)
{
E subject = checkAndAddSubjUri(pom.getTriplesMap().getId(), subjUri);
if(pom.getObject().getRefObjectMap() == null)
{
addValue(pom, subject, predicateUri, objectUri);
return;
}
String parentTriplesMapId = pom.getObject().getRefObjectMap().getParentTriplesMap().getId();
E object = getGeneratedObject(parentTriplesMapId, objectUri);
String refParentObjectTriplesMapId = pom.getObject().getRefObjectMap().getParentTriplesMap().getId();
if(object == null || rootTriplesMapIds.isEmpty() || rootTriplesMapIds.contains(refParentObjectTriplesMapId))
{
addValue(pom, subject, predicateUri, objectUri);
return;
}
addValue(pom, subject, predicateUri, object);
}
protected abstract void addValue(PredicateObjectMap pom, E subject, String predicateUri, Object object);
protected abstract void addValueToArray(PredicateObjectMap pom, E subject, Object object,
String shortHandPredicateURI);
@Override
public void finishRow() {
}
@Override
public void flush() {
outWriter.flush();
}
@Override
public abstract void close();
@Override
public void outputTripleWithURIObject(PredicateObjectMap predicateObjectMap,
String subjUri, String predicateUri,
String objectUri) {
addURIObject(predicateObjectMap, subjUri, predicateUri, objectUri);
}
@Override
public void outputTripleWithLiteralObject( PredicateObjectMap predicateObjectMap,
String subjUri, String predicateUri, String value,
String literalType, String language) {
E subject = checkAndAddSubjUri(predicateObjectMap.getTriplesMap().getId(), subjUri);
//TODO should literal type be ignored?
addValue(predicateObjectMap, subject, predicateUri, convertLiteral(value, literalType, language));
}
@Override
public void outputQuadWithLiteralObject( PredicateObjectMap predicateObjectMap,
String subjUri, String predicateUri, String value,
String literalType, String language, String graph) {
E subject = checkAndAddSubjUri(predicateObjectMap.getTriplesMap().getId(), subjUri);
//TODO should literal type be ignored?
//TODO should graph be ignored?
addValue(predicateObjectMap, subject, predicateUri, convertLiteral(value, literalType, language));
}
public void addPrefixes(Collection<Prefix> prefixes) {
shortHandURIGenerator.addPrefixes(prefixes);
}
public E getGeneratedObject(String triplesMapId, String generatedObjectUri)
{
ConcurrentHashMap<String, E> generatedObjects = this.generatedObjectsByTriplesMapId.get(triplesMapId);
return getGeneratedObject(generatedObjects, generatedObjectUri);
}
protected E getGeneratedObject(
ConcurrentHashMap<String, E> generatedObjects, String generatedObjectUri) {
if(null == generatedObjects)
{
return null;
}
return generatedObjects.get(generatedObjectUri);
}
public void addRootTriplesMapId(String rootTriplesMapId) {
rootTriplesMapIds.add(rootTriplesMapId);
this.rootObjectsByTriplesMapId.putIfAbsent(rootTriplesMapId, new ConcurrentHashMap<String, E>());
}
public void addRootTriplesMapIds(Collection<String> rootTriplesMapIds) {
for(String rootTriplesMapId : rootTriplesMapIds)
{
this.rootTriplesMapIds.add(rootTriplesMapId);
this.rootObjectsByTriplesMapId.putIfAbsent(rootTriplesMapId, new ConcurrentHashMap<String, E>());
}
}
protected abstract void collapseSameType(E obj);
protected abstract Object generateLanguageLiteral(Object literal, String language);
protected Object convertLiteral(String value, String literalType, String language) {
Object literalObj = generateLiteralWithType(value, literalType);
if(language != null && !language.equals("")) {
literalObj = generateLanguageLiteral(literalObj, language);
}
return literalObj;
}
protected Object generateLiteralWithType(String value, String literalType) {
if (numericLiteralTypes.contains(literalType)) {
ParsePosition parsePosition = new ParsePosition(0);
Number n = NumberFormat.getNumberInstance(Locale.US).parse(value, parsePosition);
if (parsePosition.getErrorIndex() != -1 || parsePosition.getIndex() < value.length())
return value;
else
return n;
}
if (literalType != null && literalType.equals("http://www.w3.org/2001/XMLSchema#boolean")) {
if (value.trim().equalsIgnoreCase("false"))
return false;
else if (value.trim().equalsIgnoreCase("true"))
return true;
}
return value;
}
public abstract E getNewObject(String triplesMapId, String subjUri);
}