package org.simantics.interop.update.model; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import org.eclipse.core.runtime.IProgressMonitor; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.Statement; import org.simantics.db.VirtualGraph; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.interop.test.GraphChanges; /** * * @author Marko Luukkainen * */ public abstract class UpdateOperations { private List operations = new ArrayList(); private Map resourceMap = new HashMap(); private Map statementMap = new HashMap(); private GraphChanges changes; private int chunkSize = -1; public UpdateOperations(GraphChanges changes) { this.changes = changes; } public UpdateOp getUpdateOp(Resource r) { return resourceMap.get(r); } public UpdateOp getUpdateOp(Statement s) { return statementMap.get(s); } public int getChunkSize() { return chunkSize; } public void setChunkSize(int chunkSize) { this.chunkSize = chunkSize; } /** * Applies all changes. * * @param graph * @throws DatabaseException */ public void applyAll(WriteGraph graph) throws DatabaseException { List list = operations; apply(graph, list); } /** * Applies selected changes. * @param graph * @throws DatabaseException */ public void applySelected(WriteGraph graph) throws DatabaseException { List list = new ArrayList(); for (UpdateOp op : operations) { if (op.selected()) list.add(op); } apply(graph, list); } /** * Applies all changes with chunked DB writes. * * @param session * @throws DatabaseException */ public void applyAll(Session session, VirtualGraph vg) throws DatabaseException { List list = operations; apply(session, list, vg); } /** * Applies selected changes with chunked DB writes. * * @param session * @throws DatabaseException */ public void applySelected(Session session, VirtualGraph vg) throws DatabaseException { List list = new ArrayList(); for (UpdateOp op : operations) { if (op.selected()) list.add(op); } apply(session, list, vg); } protected void apply(WriteGraph graph, List list) throws DatabaseException { for (UpdateOp op : list) { apply(graph, op); } } protected void apply(Session session, List list, VirtualGraph vg) throws DatabaseException { if (getChunkSize() > 0) { for (int s = 0; s < list.size(); ) { int e = s + getChunkSize(); if (e > list.size()) e = list.size(); List subList = list.subList(s, e); session.syncRequest(new WriteRequest(vg) { @Override public void perform(WriteGraph graph) throws DatabaseException { for (UpdateOp op : subList) { apply(graph, op); } } }); s = e; } } else { session.syncRequest(new WriteRequest(vg) { @Override public void perform(WriteGraph graph) throws DatabaseException { for (UpdateOp op : list) { apply(graph, op); } } }); } } public List getOperations() { return operations; } public GraphChanges getChanges() { return changes; } public Map getResourceMap() { return resourceMap; } public Map getStatementMap() { return statementMap; } private void apply(WriteGraph g, UpdateOp op) throws DatabaseException { Stack stack = new Stack(); _apply(g, stack, op); } private void _apply(WriteGraph g, Stack stack, UpdateOp op) throws DatabaseException { if (op.applied()) return; if (stack.contains(op)) { op.apply(g); return; } stack.push(op); for (UpdateOp pop : op.getParentOps()) if (op.requiresOp(pop)) { if (!pop.applied()) _apply(g, stack, pop); } for (UpdateOp sop : op.getSubOps()) if (op.requiresOp(sop)) { if (!sop.applied()) _apply(g, stack, sop); } stack.pop(); op.apply(g); } protected List getOps() { List list = new ArrayList(operations.size()); list.addAll(operations); return list; } protected void addOp(Resource r, UpdateOp op) { resourceMap.put(r, op); operations.add(op); } protected void addOp(Statement s, UpdateOp op) { statementMap.put(s, op); operations.add(op); } protected void replaceOp(Resource r, UpdateOp op) { UpdateOp oldOp = resourceMap.remove(r); if (oldOp != null) { operations.remove(oldOp); } resourceMap.put(r, op); operations.add(op); } protected UpdateOp getOP(Resource r) { return resourceMap.get(r); } protected UpdateOp getOP(Statement r) { return statementMap.get(r); } public abstract void populate(ReadGraph g) throws DatabaseException; /** * Secondary populate method. Override this for chunked DB operations. * @param session * @throws DatabaseException */ public void populate(Session session, IProgressMonitor monitor) throws DatabaseException { session.syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { populate(graph); } }); } protected boolean compares(Resource r1, Resource r2) { if (r1.equals(r2)) return true; if (changes.getComparable().contains(r1, r2)) return true; return false; } }