-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) {
+ @Override
+ public void run0(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().propagateChangesInQueryCache(writer);
+ session.fireMetadataListeners(writer, cs);
+ session.getQueryProvider2().listening.fireListeners(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);
+ }
+
+}