]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/UndoRedoSupportImpl.java
Defer change set disposal in State.commitWriteTransaction
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / UndoRedoSupportImpl.java
index a50a6eb3e10b64aebaa66e3099b73adbf54890d1..0f8d9706c6814d089120f71996a5ebcd10fd3b62 100644 (file)
-package fi.vtt.simantics.procore.internal;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-import org.simantics.db.Operation;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.SessionVariables;\r
-import org.simantics.db.UndoContext;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.CommentMetadata;\r
-import org.simantics.db.common.CommitMetadata;\r
-import org.simantics.db.common.UndoMetadata;\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.impl.graph.WriteGraphImpl;\r
-import org.simantics.db.impl.query.QueryProcessor.SessionTask;\r
-import org.simantics.db.service.ExternalOperation;\r
-import org.simantics.db.service.ManagementSupport;\r
-import org.simantics.db.service.UndoRedoSupport;\r
-import org.simantics.scl.runtime.function.FunctionImpl1;\r
-import org.simantics.utils.DataContainer;\r
-\r
-import fi.vtt.simantics.procore.internal.SessionImplSocket.TaskHelper;\r
-\r
-public class UndoRedoSupportImpl implements UndoRedoSupport {\r
-    final private boolean DEBUG = SessionImplSocket.DEBUG;\r
-    final private SessionImplSocket session;\r
-    final ManagementSupport managementSupport;\r
-\r
-    UndoRedoSupportImpl(SessionImplSocket session) {\r
-        this.session = session;\r
-        this.managementSupport = session.getService(ManagementSupport.class);\r
-    }\r
-\r
-    @Override\r
-    public Operation undo(final Collection<Operation> ops) throws DatabaseException {\r
-        if (null == ops || ops.size() < 1)\r
-            throw new IllegalArgumentException("At least one operation must be defined.");\r
-        final Operation fop = (Operation)ops.toArray()[0];\r
-        final DataContainer<Long> id = new DataContainer<Long>(0L);\r
-        final TaskHelper th = new TaskHelper("Undo");\r
-        session.requestManager.scheduleWrite(new SessionTask(null, 0) {\r
-            @Override\r
-            public void run(int thread) {\r
-                session.flushCounter = 0;\r
-                session.clusterStream.reallyFlush();\r
-                ClientChangesImpl cs = new ClientChangesImpl(session);\r
-                if (session.clientChanges == null)\r
-                    session.clientChanges = cs;\r
-                WriteGraphImpl writer = WriteGraphImpl.create(session.getQueryProvider2(), session.writeSupport, null);\r
-                session.writeState = new WriteState<Object>(writer, th.writeTraits, th.sema, th.proc);\r
-                try {\r
-                    SynchronizeContext context = new SynchronizeContext(session, cs, 1);\r
-                    boolean potentialConflicts = session.graphSession.undo(ops, context);\r
-                    if (potentialConflicts)\r
-                        th.throw_("Server thinks that there might be potential conflicts with this undo operation.");\r
-                    final boolean undo = true;\r
-                    if (!context.isOk(undo)) // this is a blocking operation\r
-                        th.throw_("Trouble with server reply.");\r
-                } catch (Throwable e) {\r
-                    if (DEBUG)\r
-                        e.printStackTrace();\r
-                    th.throwableSet(e);\r
-                    th.sema.release();\r
-                    return;\r
-                }\r
-                try {\r
-                    writer.markUndoPoint(); // Undo should form it's own operation.\r
-                    // Add a comment to metadata.\r
-                    CommentMetadata cm = writer.getMetadata(CommentMetadata.class);\r
-                    UndoMetadata um = writer.getMetadata(UndoMetadata.class);\r
-                    UndoMetadata pum = getComment4Undo(fop.getId());\r
-                    if (null != pum) {\r
-                        writer.addMetadata(um.add(pum));\r
-                        um.setTypeAndRange(pum);\r
-                    }\r
-                    writer.addMetadata(um.add("Undo operation " + fop.getId() + "."));\r
-                    Operation ope = fop;\r
-                    if (ops.size() > 1) {\r
-                        writer.addMetadata(um.add("Undo " + ops.size() + " change sets."));\r
-                        writer.addMetadata(um.add("First change set was " + fop.getCSId() + "."));\r
-                        Operation lop = (Operation)ops.toArray()[ops.size()-1];\r
-                        writer.addMetadata(um.add("Last change set was " + lop.getCSId() + "."));\r
-                        ope = lop;\r
-                    }\r
-                    writer.addMetadata(cm.add(getComment(ope.getId())));\r
-                    if (null == pum || pum.getBeginCSId() == 0) {\r
-                        um.setTypeAndRange(false, ope.getId(), ope.getCSId());\r
-                        writer.addMetadata(um);\r
-                    }\r
-                    session.getQueryProvider2().performDirtyUpdates(writer);\r
-                    session.fireMetadataListeners(writer, cs);\r
-                    session.getQueryProvider2().performScheduledUpdates(writer);\r
-                    session.fireReactionsToSynchronize(cs);\r
-                    session.fireSessionVariableChange(SessionVariables.QUEUED_WRITES);\r
-                    session.printDiagnostics();\r
-                    long headChangeSetId = session.state.getHeadRevisionId();\r
-                    id.set(headChangeSetId+1);\r
-                } catch (Throwable e) {\r
-                    if (DEBUG)\r
-                        e.printStackTrace();\r
-                    Logger.defaultLogError(e);\r
-                    th.throwableSet(e);\r
-                }\r
-            }\r
-        });\r
-        session.acquire(th.sema, th.writeTraits);\r
-        th.throwableCheck();\r
-        long headChangeSetId = session.state.getHeadRevisionId();\r
-        if (id.get() == headChangeSetId+1)\r
-            return null; // Empty undo operation;\r
-\r
-        final ArrayList<ExternalOperation> externalRedos = new ArrayList<ExternalOperation>();\r
-        GraphSession.forExternals(ops, new FunctionImpl1<ExternalOperation, Boolean>() {\r
-\r
-               @Override\r
-               public Boolean apply(final ExternalOperation op) {\r
-                       externalRedos.add(new ExternalOperation() {\r
-\r
-                                       @Override\r
-                                       public void undo() {\r
-                                               op.redo();\r
-                                       }\r
-\r
-                                       @Override\r
-                                       public void redo() {\r
-                                               op.undo();\r
-                                       }\r
-\r
-                                       @Override\r
-                                       public boolean isDisposed() {\r
-                                               return op.isDisposed();\r
-                                       }\r
-\r
-                       });\r
-                       return true;\r
-               }\r
-\r
-       });\r
-\r
-        return new OperationImpl(id.get(), id.get(), externalRedos);\r
-\r
-    }\r
-    private CommentMetadata getComment(long id) {\r
-        Collection<CommentMetadata> metadata;\r
-        try {\r
-            metadata = managementSupport.getMetadata(id, id, CommentMetadata.class);\r
-            if (metadata.size() > 0)\r
-                return metadata.iterator().next();\r
-        } catch (Throwable t) {\r
-            Logger.defaultLogError(t);\r
-        }\r
-        return null;\r
-    }\r
-    private UndoMetadata getComment4Undo(long id) {\r
-        Collection<UndoMetadata> metadata;\r
-        try {\r
-            metadata = managementSupport.getMetadata(id, id, UndoMetadata.class);\r
-            if (metadata.size() > 0)\r
-                return metadata.iterator().next();\r
-        } catch (Throwable t) {\r
-            Logger.defaultLogError(t);\r
-        }\r
-        return null;\r
-    }\r
-    @Override\r
-    public void undo(Operation op)\r
-    throws DatabaseException {\r
-        Collection<Operation> ops = new ArrayList<Operation>();\r
-        ops.add(op);\r
-        undo(ops);\r
-    }\r
-\r
-    @Override\r
-    public Operation getCurrent() {\r
-        return session.state.getLastOperation();\r
-    }\r
-\r
-    @Override\r
-    public int undo(Session session, int count)\r
-    throws DatabaseException {\r
-        return undoAndReturnOperations(session, count).size();\r
-    }\r
-\r
-    @Override\r
-    public List<Operation> undoAndReturnOperations(Session session, int count)\r
-    throws DatabaseException {\r
-        if ( count < 1)\r
-            return Collections.emptyList();\r
-        if (!(session instanceof SessionImplDb))\r
-            return Collections.emptyList();\r
-        SessionImplDb s = (SessionImplDb)session;\r
-        return s.graphSession.undoContext.undo(this, count);\r
-    }\r
-\r
-    @Override\r
-    public List<Operation> redo(Session session, int count)\r
-    throws DatabaseException {\r
-        if ( count < 1)\r
-            return Collections.emptyList();\r
-        if (!(session instanceof SessionImplDb))\r
-            return Collections.emptyList();\r
-        SessionImplDb s = (SessionImplDb)session;\r
-        return s.graphSession.undoContext.redo(this, count);\r
-    }\r
-\r
-    @Override\r
-    public int undoTo(Session session, long changeSet)\r
-        throws DatabaseException {\r
-        if (!(session instanceof SessionImplDb) || changeSet < 1)\r
-            return 0;\r
-        SessionImplDb s = (SessionImplDb)session;\r
-        long head = s.graphSession.getLastChangeSetId();\r
-        int SIZE = (int)(head - changeSet);\r
-        if (SIZE < 1)\r
-            return 0;\r
-        s.graphSession.undoContext.clear();\r
-        Vector<Operation> ops = new Vector<Operation>(SIZE);\r
-        ops.setSize(SIZE);\r
-        long id = changeSet;\r
-        for (int i = 0; i<SIZE; ++i) {\r
-            ++id;\r
-            Operation o = new OperationImpl(id, id);\r
-            ops.setElementAt(o, i);\r
-        }\r
-        undo(ops);\r
-        return SIZE;\r
-    }\r
-    @Override\r
-    public int initUndoListFrom(Session session, long changeSet)\r
-        throws DatabaseException {\r
-        if (!(session instanceof SessionImplDb) || changeSet < 1)\r
-            return 0;\r
-        SessionImplDb s = (SessionImplDb)session;\r
-        long head = s.graphSession.getLastChangeSetId();\r
-        int SIZE = (int)(head - changeSet + 1);\r
-        if (SIZE < 1)\r
-            return 0;\r
-        ManagementSupport ms = session.getService(ManagementSupport.class);\r
-        Collection<CommitMetadata> metadata = ms.getMetadata(changeSet, head, CommitMetadata.class);\r
-        if (metadata.size() != SIZE)\r
-            return 0;\r
-        s.graphSession.undoContext.clear();\r
-        long first = 0;\r
-        Iterator<CommitMetadata> it = metadata.iterator();\r
-        long csid = changeSet;\r
-        SIZE += csid;\r
-        for (; csid<SIZE; ++csid) {\r
-            CommitMetadata md = it.next();\r
-            if (first == 0) {\r
-                if (md.opid != 0 && md.opid != csid)\r
-                    continue;\r
-                first = csid;\r
-            }\r
-            long id = md.opid != 0 ? md.opid : csid;\r
-            Operation op = new OperationImpl(id, csid);\r
-            s.graphSession.undoContext.commitOk(op);\r
-        }\r
-        return (int)(csid - first);\r
-    }\r
-    @Override\r
-    public UndoContext getUndoContext(Session session) {\r
-        if (session instanceof SessionImplSocket) {\r
-            GraphSession graphSession = ((SessionImplSocket)session).graphSession;\r
-            return graphSession != null ? graphSession.undoContext : null;\r
-        }\r
-        return null;\r
-    }\r
-    @Override\r
-    public void subscribe(ChangeListener changeListener) {\r
-        session.graphSession.undoContext.addChangeListener(changeListener);\r
-    }\r
-    @Override\r
-    public void cancel(ChangeListener changelistener) {\r
-        session.graphSession.undoContext.removeChangeListener(changelistener);\r
-    }\r
-\r
-    @Override\r
-    public void addExternalOperation(WriteGraph graph, ExternalOperation op) {\r
-        if (!(session instanceof SessionImplDb))\r
-            return;\r
-        SessionImplDb s = (SessionImplDb)session;\r
-        s.graphSession.undoContext.addExternalOperation(op);\r
-    }\r
-\r
-}\r
+package fi.vtt.simantics.procore.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.simantics.db.Operation;
+import org.simantics.db.Session;
+import org.simantics.db.SessionVariables;
+import org.simantics.db.UndoContext;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.CommentMetadata;
+import org.simantics.db.common.CommitMetadata;
+import org.simantics.db.common.UndoMetadata;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.impl.graph.WriteGraphImpl;
+import org.simantics.db.impl.query.QueryProcessor.SessionTask;
+import org.simantics.db.service.ExternalOperation;
+import org.simantics.db.service.ManagementSupport;
+import org.simantics.db.service.UndoRedoSupport;
+import org.simantics.scl.runtime.function.FunctionImpl1;
+import org.simantics.utils.DataContainer;
+
+import fi.vtt.simantics.procore.internal.SessionImplSocket.TaskHelper;
+
+public class UndoRedoSupportImpl implements UndoRedoSupport {
+    final private boolean DEBUG = SessionImplSocket.DEBUG;
+    final private SessionImplSocket session;
+    final ManagementSupport managementSupport;
+
+    UndoRedoSupportImpl(SessionImplSocket session) {
+        this.session = session;
+        this.managementSupport = session.getService(ManagementSupport.class);
+    }
+
+    @Override
+    public Operation undo(final Collection<Operation> ops) throws DatabaseException {
+        if (null == ops || ops.size() < 1)
+            throw new IllegalArgumentException("At least one operation must be defined.");
+        final Operation fop = (Operation)ops.toArray()[0];
+        final DataContainer<Long> id = new DataContainer<Long>(0L);
+        final TaskHelper th = new TaskHelper("Undo");
+        session.requestManager.scheduleWrite(new SessionTask(null, 0) {
+            @Override
+            public void run(int thread) {
+                session.flushCounter = 0;
+                session.clusterStream.reallyFlush();
+                ClientChangesImpl cs = new ClientChangesImpl(session);
+                if (session.clientChanges == null)
+                    session.clientChanges = cs;
+                WriteGraphImpl writer = WriteGraphImpl.create(session.getQueryProvider2(), session.writeSupport, null);
+                session.writeState = new WriteState<Object>(writer, th.writeTraits, th.sema, th.proc);
+                try {
+                    SynchronizeContext context = new SynchronizeContext(session, cs, 1);
+                    boolean potentialConflicts = session.graphSession.undo(ops, context);
+                    if (potentialConflicts)
+                        th.throw_("Server thinks that there might be potential conflicts with this undo operation.");
+                    final boolean undo = true;
+                    if (!context.isOk(undo)) // this is a blocking operation
+                        th.throw_("Trouble with server reply.");
+                } catch (Throwable e) {
+                    if (DEBUG)
+                        e.printStackTrace();
+                    th.throwableSet(e);
+                    th.sema.release();
+                    return;
+                }
+                try {
+                    writer.markUndoPoint(); // Undo should form it's own operation.
+                    // Add a comment to metadata.
+                    CommentMetadata cm = writer.getMetadata(CommentMetadata.class);
+                    UndoMetadata um = writer.getMetadata(UndoMetadata.class);
+                    UndoMetadata pum = getComment4Undo(fop.getId());
+                    if (null != pum) {
+                        writer.addMetadata(um.add(pum));
+                        um.setTypeAndRange(pum);
+                    }
+                    writer.addMetadata(um.add("Undo operation " + fop.getId() + "."));
+                    Operation ope = fop;
+                    if (ops.size() > 1) {
+                        writer.addMetadata(um.add("Undo " + ops.size() + " change sets."));
+                        writer.addMetadata(um.add("First change set was " + fop.getCSId() + "."));
+                        Operation lop = (Operation)ops.toArray()[ops.size()-1];
+                        writer.addMetadata(um.add("Last change set was " + lop.getCSId() + "."));
+                        ope = lop;
+                    }
+                    writer.addMetadata(cm.add(getComment(ope.getId())));
+                    if (null == pum || pum.getBeginCSId() == 0) {
+                        um.setTypeAndRange(false, ope.getId(), ope.getCSId());
+                        writer.addMetadata(um);
+                    }
+                    session.getQueryProvider2().performDirtyUpdates(writer);
+                    session.fireMetadataListeners(writer, cs);
+                    session.getQueryProvider2().performScheduledUpdates(writer);
+                    session.fireReactionsToSynchronize(cs);
+                    session.fireSessionVariableChange(SessionVariables.QUEUED_WRITES);
+                    session.printDiagnostics();
+                    long headChangeSetId = session.state.getHeadRevisionId();
+                    id.set(headChangeSetId+1);
+                } catch (Throwable e) {
+                    if (DEBUG)
+                        e.printStackTrace();
+                    Logger.defaultLogError(e);
+                    th.throwableSet(e);
+                } finally {
+                    cs.dispose();
+                }
+            }
+        });
+        session.acquire(th.sema, th.writeTraits);
+        th.throwableCheck();
+        long headChangeSetId = session.state.getHeadRevisionId();
+        if (id.get() == headChangeSetId+1)
+            return null; // Empty undo operation;
+
+        final ArrayList<ExternalOperation> externalRedos = new ArrayList<ExternalOperation>();
+        GraphSession.forExternals(ops, new FunctionImpl1<ExternalOperation, Boolean>() {
+
+               @Override
+               public Boolean apply(final ExternalOperation op) {
+                       externalRedos.add(new ExternalOperation() {
+
+                                       @Override
+                                       public void undo() {
+                                               op.redo();
+                                       }
+
+                                       @Override
+                                       public void redo() {
+                                               op.undo();
+                                       }
+
+                                       @Override
+                                       public boolean isDisposed() {
+                                               return op.isDisposed();
+                                       }
+
+                       });
+                       return true;
+               }
+
+       });
+
+        return new OperationImpl(id.get(), id.get(), externalRedos);
+
+    }
+    private CommentMetadata getComment(long id) {
+        Collection<CommentMetadata> metadata;
+        try {
+            metadata = managementSupport.getMetadata(id, id, CommentMetadata.class);
+            if (metadata.size() > 0)
+                return metadata.iterator().next();
+        } catch (Throwable t) {
+            Logger.defaultLogError(t);
+        }
+        return null;
+    }
+    private UndoMetadata getComment4Undo(long id) {
+        Collection<UndoMetadata> metadata;
+        try {
+            metadata = managementSupport.getMetadata(id, id, UndoMetadata.class);
+            if (metadata.size() > 0)
+                return metadata.iterator().next();
+        } catch (Throwable t) {
+            Logger.defaultLogError(t);
+        }
+        return null;
+    }
+    @Override
+    public void undo(Operation op)
+    throws DatabaseException {
+        Collection<Operation> ops = new ArrayList<Operation>();
+        ops.add(op);
+        undo(ops);
+    }
+
+    @Override
+    public Operation getCurrent() {
+        return session.state.getLastOperation();
+    }
+
+    @Override
+    public int undo(Session session, int count)
+    throws DatabaseException {
+        return undoAndReturnOperations(session, count).size();
+    }
+
+    @Override
+    public List<Operation> undoAndReturnOperations(Session session, int count)
+    throws DatabaseException {
+        if ( count < 1)
+            return Collections.emptyList();
+        if (!(session instanceof SessionImplDb))
+            return Collections.emptyList();
+        SessionImplDb s = (SessionImplDb)session;
+        return s.graphSession.undoContext.undo(this, count);
+    }
+
+    @Override
+    public List<Operation> redo(Session session, int count)
+    throws DatabaseException {
+        if ( count < 1)
+            return Collections.emptyList();
+        if (!(session instanceof SessionImplDb))
+            return Collections.emptyList();
+        SessionImplDb s = (SessionImplDb)session;
+        return s.graphSession.undoContext.redo(this, count);
+    }
+
+    @Override
+    public int undoTo(Session session, long changeSet)
+        throws DatabaseException {
+        if (!(session instanceof SessionImplDb) || changeSet < 1)
+            return 0;
+        SessionImplDb s = (SessionImplDb)session;
+        long head = s.graphSession.getLastChangeSetId();
+        int SIZE = (int)(head - changeSet);
+        if (SIZE < 1)
+            return 0;
+        s.graphSession.undoContext.clear();
+        Vector<Operation> ops = new Vector<Operation>(SIZE);
+        ops.setSize(SIZE);
+        long id = changeSet;
+        for (int i = 0; i<SIZE; ++i) {
+            ++id;
+            Operation o = new OperationImpl(id, id);
+            ops.setElementAt(o, i);
+        }
+        undo(ops);
+        return SIZE;
+    }
+    @Override
+    public int initUndoListFrom(Session session, long changeSet)
+        throws DatabaseException {
+        if (!(session instanceof SessionImplDb) || changeSet < 1)
+            return 0;
+        SessionImplDb s = (SessionImplDb)session;
+        long head = s.graphSession.getLastChangeSetId();
+        int SIZE = (int)(head - changeSet + 1);
+        if (SIZE < 1)
+            return 0;
+        ManagementSupport ms = session.getService(ManagementSupport.class);
+        Collection<CommitMetadata> metadata = ms.getMetadata(changeSet, head, CommitMetadata.class);
+        if (metadata.size() != SIZE)
+            return 0;
+        s.graphSession.undoContext.clear();
+        long first = 0;
+        Iterator<CommitMetadata> it = metadata.iterator();
+        long csid = changeSet;
+        SIZE += csid;
+        for (; csid<SIZE; ++csid) {
+            CommitMetadata md = it.next();
+            if (first == 0) {
+                if (md.opid != 0 && md.opid != csid)
+                    continue;
+                first = csid;
+            }
+            long id = md.opid != 0 ? md.opid : csid;
+            Operation op = new OperationImpl(id, csid);
+            s.graphSession.undoContext.commitOk(op);
+        }
+        return (int)(csid - first);
+    }
+    @Override
+    public UndoContext getUndoContext(Session session) {
+        if (session instanceof SessionImplSocket) {
+            GraphSession graphSession = ((SessionImplSocket)session).graphSession;
+            return graphSession != null ? graphSession.undoContext : null;
+        }
+        return null;
+    }
+    @Override
+    public void subscribe(ChangeListener changeListener) {
+        session.graphSession.undoContext.addChangeListener(changeListener);
+    }
+    @Override
+    public void cancel(ChangeListener changelistener) {
+        session.graphSession.undoContext.removeChangeListener(changelistener);
+    }
+
+    @Override
+    public void addExternalOperation(WriteGraph graph, ExternalOperation op) {
+        if (!(session instanceof SessionImplDb))
+            return;
+        SessionImplDb s = (SessionImplDb)session;
+        s.graphSession.undoContext.addExternalOperation(op);
+    }
+
+}