package org.aksw.jena_sparql_api.update_old;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.aksw.commons.util.reflect.MultiMethod;
import org.aksw.jena_sparql_api.core.QueryExecutionFactory;
import org.aksw.jena_sparql_api.utils.QueryUtils;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.query.Query;
import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.graph.GraphFactory;
import org.apache.jena.sparql.modify.request.UpdateDataDelete;
import org.apache.jena.sparql.modify.request.UpdateDataInsert;
import org.apache.jena.sparql.modify.request.UpdateModify;
import org.apache.jena.sparql.syntax.Element;
import org.apache.jena.update.Update;
import org.apache.jena.update.UpdateFactory;
import org.apache.jena.update.UpdateRequest;
public class UpdateGraph
{
private Set<UpdateListenerOld> graphListeners = new HashSet<UpdateListenerOld>();
public Set<UpdateListenerOld> getPreUpdateListeners()
{
return graphListeners;
}
// Important: Ensure that the qef does not use caching
private QueryExecutionFactory qef;
//
private int batchSize = 128;
public UpdateGraph(QueryExecutionFactory qef)
{
this.qef = qef;
}
public static Map<Node, Graph> quadsToGraphs(Collection<Quad> quads) {
Map<Node, Graph> result = new HashMap<Node, Graph>();
for(Quad quad : quads) {
Triple triple = quad.asTriple();
Node graphName = quad.getGraph();
Graph graph = result.get(graphName);
if(graph == null) {
graph = GraphFactory.createDefaultGraph();
result.put(graphName, graph);
}
graph.add(triple);
}
return result;
}
private void insert(Collection<Quad> quads) {
if(quads.isEmpty()) {
return;
}
notifyPreUpdate(quads, null);
for(Entry<Node, Graph> entry : quadsToGraphs(quads).entrySet()) {
Model model = ModelFactory.createModelForGraph(entry.getValue());
qef.insert(model, entry.getKey().toString());
}
notifyPostUpdate(quads, null);
}
private void notifyPreUpdate(Collection<Quad> inserts, Collection<Quad> deletes) {
for(UpdateListenerOld graphListener : graphListeners) {
graphListener.onPreBatchStart();
if(inserts != null) {
for(Quad quad : inserts) {
graphListener.onPreInsert(quad);
}
}
if(deletes != null) {
for(Quad quad : deletes) {
graphListener.onPreDelete(quad);
}
}
graphListener.onPreBatchEnd();
}
}
private void notifyPostUpdate(Collection<Quad> inserts, Collection<Quad> deletes) {
for(UpdateListenerOld graphListener : graphListeners) {
graphListener.onPostBatchStart();
if(inserts != null) {
for(Quad quad : inserts) {
graphListener.onPostInsert(quad);
}
}
if(deletes != null) {
for(Quad quad : deletes) {
graphListener.onPostDelete(quad);
}
}
graphListener.onPostBatchEnd();
}
}
private void delete(Collection<Quad> quads) {
if(quads.isEmpty()) {
return;
}
notifyPreUpdate(null, quads);
for(Entry<Node, Graph> entry : quadsToGraphs(quads).entrySet()) {
Model model = ModelFactory.createModelForGraph(entry.getValue());
qef.remove(model, entry.getKey().toString());
}
notifyPostUpdate(null, quads);
}
/*
protected void startBatch()
{
for(GraphListener graphListener : preChangeGraphListeners) {
graphListener.onBatchStart();
}
}
protected void endBatch()
{
for(GraphListener graphListener : preChangeGraphListeners) {
graphListener.onBatchEnd();
}
}*/
@SuppressWarnings("unused")
private void _update(UpdateModify update)
{
Element wherePattern = update.getWherePattern();
Query query = QueryUtils.elementToQuery(wherePattern);
String queryStr = query.toString();
// TODO Limit and offset...
ResultSet rs = qef.createQueryExecution(queryStr).execSelect();
Set<Quad> inserts = new HashSet<Quad>();
Set<Quad> deletes = new HashSet<Quad>();
while(rs.hasNext()) {
Binding binding = rs.nextBinding();
Set<Quad> i = QueryUtils.instanciate(update.getInsertQuads(), binding);
Set<Quad> d = QueryUtils.instanciate(update.getDeleteQuads(), binding);
inserts.addAll(i);
deletes.addAll(d);
if(inserts.size() > batchSize) {
insert(inserts);
inserts.clear();
}
if(deletes.size() > batchSize) {
delete(deletes);
deletes.clear();
}
}
insert(inserts);
delete(deletes);
}
@SuppressWarnings("unused")
private void _update(UpdateDataInsert update)
{
insert(update.getQuads());
}
@SuppressWarnings("unused")
private void _update(UpdateDataDelete update)
{
delete(update.getQuads());
}
public void executeUpdate(String queryStr)
{
UpdateRequest request = new UpdateRequest();
UpdateFactory.parse(request, queryStr);
for(Update update : request.getOperations()) {
MultiMethod.invoke(this, "_update", update);
}
}
}