return new CloseableIteration<BindingSet, QueryEvaluationException>() {
private Cursor cursor = query.fetchLazy(50);
private UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_ALL_SCHEMES | UrlValidator.ALLOW_LOCAL_URLS);
// in case we need to split one SQL query row into several SPARQL query rows, we do it by creating
// a temporary iterator
private Iterator<BindingSet> splitBindings = null;
@Override
public void close() throws QueryEvaluationException {
if(!cursor.isClosed()) {
cursor.close();
}
try {
if(!connection.getAutoCommit()) {
connection.commit();
}
connection.close();
} catch (SQLException e) {
log.error("SQL exception while closing JDBC connection",e);
}
em.close();
}
@Override
public boolean hasNext() throws QueryEvaluationException {
return (splitBindings !=null && splitBindings.hasNext()) || cursor.hasNext();
}
@Override
public BindingSet next() throws QueryEvaluationException {
if(splitBindings != null) {
return splitBindings.next();
} else {
Record record = cursor.fetchOne();
// check if the result contains multiple SPARQL bindings in a single row or
// only one SPARQL row; we can do this by checking whether the first result starts
// with _multi
if(record.getField(0).getName().startsWith("_multi")) {
log.info("transforming single-row SQL result into multi-row SPARQL result");
List<BindingSet> results = new ArrayList<BindingSet>();
for(int i=1; true; i++) {
MapBindingSet result = new MapBindingSet();
for(String var : mapper.getProjectedVariables()) {
if(var.startsWith("_multi") && var.endsWith("_"+i)) {
Long nodeId = record.getValue(var, Long.class);
if(nodeId != null) {
Value value = em.find(KiWiNode.class, nodeId);
result.addBinding(var.substring(var.indexOf('_',1)+1,var.lastIndexOf('_')),value);
}
}
}
for(Map.Entry<String,Class> ext : mapper.getExtensionVariables().entrySet()) {
String var = ext.getKey();
if(var.startsWith("_multi") && var.endsWith("_"+i)) {
Object val = record.getValue(ext.getKey(),ext.getValue());
// this is truly a hack: we check whether the string is a URI, and if yes create a URI resource...
// it would be better to carry over this information from the value constants
if(urlValidator.isValid(val.toString())) {
URI value = new URIImpl(val.toString());
result.addBinding(var.substring(var.indexOf('_',1)+1,var.lastIndexOf('_')),value);
} else {
String type = LiteralCommons.getXSDType(ext.getValue());
// we only create an in-memory representation of the value, the LMF methods
// would automatically persist it, so we create a Sesame value
Value value = new LiteralImpl(val.toString(),sesameService.getValueFactory().createURI(type));
result.addBinding(var.substring(var.indexOf('_',1)+1,var.lastIndexOf('_')),value);
}
}
}
if(result.size() == 0) {
break;
} else {
results.add(result);
}
}
em.clear();
splitBindings = results.iterator();
return splitBindings.next();
} else {
MapBindingSet result = new MapBindingSet();
for(String var : mapper.getProjectedVariables()) {
Long nodeId = record.getValue(var, Long.class);
if(nodeId != null) {
Value value = em.find(KiWiNode.class, nodeId);
result.addBinding(var,value);
}
}
for(Map.Entry<String,Class> ext : mapper.getExtensionVariables().entrySet()) {
Object val = record.getValue(ext.getKey(),ext.getValue());
// this is truly a hack: we check whether the string is a URI, and if yes create a URI resource...
// it would be better to carry over this information from the value constants
if(urlValidator.isValid(val.toString())) {
URI value = new URIImpl(val.toString());
result.addBinding(ext.getKey(),value);
} else {
String type = LiteralCommons.getXSDType(ext.getValue());