1 package fi.vtt.simantics.procore.internal;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.Iterator;
8 import java.util.Vector;
10 import org.simantics.db.Operation;
11 import org.simantics.db.Session;
12 import org.simantics.db.SessionVariables;
13 import org.simantics.db.UndoContext;
14 import org.simantics.db.WriteGraph;
15 import org.simantics.db.common.CommentMetadata;
16 import org.simantics.db.common.CommitMetadata;
17 import org.simantics.db.common.UndoMetadata;
18 import org.simantics.db.common.utils.Logger;
19 import org.simantics.db.exception.DatabaseException;
20 import org.simantics.db.impl.graph.WriteGraphImpl;
21 import org.simantics.db.impl.query.QueryProcessor.SessionTask;
22 import org.simantics.db.service.ExternalOperation;
23 import org.simantics.db.service.ManagementSupport;
24 import org.simantics.db.service.UndoRedoSupport;
25 import org.simantics.scl.runtime.function.FunctionImpl1;
26 import org.simantics.utils.DataContainer;
28 import fi.vtt.simantics.procore.internal.SessionImplSocket.TaskHelper;
30 public class UndoRedoSupportImpl implements UndoRedoSupport {
31 final private boolean DEBUG = SessionImplSocket.DEBUG;
32 final private SessionImplSocket session;
33 final ManagementSupport managementSupport;
35 UndoRedoSupportImpl(SessionImplSocket session) {
36 this.session = session;
37 this.managementSupport = session.getService(ManagementSupport.class);
41 public Operation undo(final Collection<Operation> ops) throws DatabaseException {
42 if (null == ops || ops.size() < 1)
43 throw new IllegalArgumentException("At least one operation must be defined.");
44 final Operation fop = (Operation)ops.toArray()[0];
45 final DataContainer<Long> id = new DataContainer<Long>(0L);
46 final TaskHelper th = new TaskHelper("Undo");
47 session.requestManager.scheduleWrite(new SessionTask(null, 0) {
49 public void run(int thread) {
50 session.flushCounter = 0;
51 session.clusterStream.reallyFlush();
52 ClientChangesImpl cs = new ClientChangesImpl(session);
53 if (session.clientChanges == null)
54 session.clientChanges = cs;
55 WriteGraphImpl writer = WriteGraphImpl.create(session.getQueryProvider2(), session.writeSupport, null);
56 session.writeState = new WriteState<Object>(writer, th.writeTraits, th.sema, th.proc);
58 SynchronizeContext context = new SynchronizeContext(session, cs, 1);
59 boolean potentialConflicts = session.graphSession.undo(ops, context);
60 if (potentialConflicts)
61 th.throw_("Server thinks that there might be potential conflicts with this undo operation.");
62 final boolean undo = true;
63 if (!context.isOk(undo)) // this is a blocking operation
64 th.throw_("Trouble with server reply.");
65 } catch (Throwable e) {
73 writer.markUndoPoint(); // Undo should form it's own operation.
74 // Add a comment to metadata.
75 CommentMetadata cm = writer.getMetadata(CommentMetadata.class);
76 UndoMetadata um = writer.getMetadata(UndoMetadata.class);
77 UndoMetadata pum = getComment4Undo(fop.getId());
79 writer.addMetadata(um.add(pum));
80 um.setTypeAndRange(pum);
82 writer.addMetadata(um.add("Undo operation " + fop.getId() + "."));
85 writer.addMetadata(um.add("Undo " + ops.size() + " change sets."));
86 writer.addMetadata(um.add("First change set was " + fop.getCSId() + "."));
87 Operation lop = (Operation)ops.toArray()[ops.size()-1];
88 writer.addMetadata(um.add("Last change set was " + lop.getCSId() + "."));
91 writer.addMetadata(cm.add(getComment(ope.getId())));
92 if (null == pum || pum.getBeginCSId() == 0) {
93 um.setTypeAndRange(false, ope.getId(), ope.getCSId());
94 writer.addMetadata(um);
96 session.getQueryProvider2().performDirtyUpdates(writer);
97 session.fireMetadataListeners(writer, cs);
98 session.getQueryProvider2().performScheduledUpdates(writer);
99 session.fireReactionsToSynchronize(cs);
100 session.fireSessionVariableChange(SessionVariables.QUEUED_WRITES);
101 session.printDiagnostics();
102 long headChangeSetId = session.state.getHeadRevisionId();
103 id.set(headChangeSetId+1);
104 } catch (Throwable e) {
107 Logger.defaultLogError(e);
112 session.acquire(th.sema, th.writeTraits);
114 long headChangeSetId = session.state.getHeadRevisionId();
115 if (id.get() == headChangeSetId+1)
116 return null; // Empty undo operation;
118 final ArrayList<ExternalOperation> externalRedos = new ArrayList<ExternalOperation>();
119 GraphSession.forExternals(ops, new FunctionImpl1<ExternalOperation, Boolean>() {
122 public Boolean apply(final ExternalOperation op) {
123 externalRedos.add(new ExternalOperation() {
136 public boolean isDisposed() {
137 return op.isDisposed();
146 return new OperationImpl(id.get(), id.get(), externalRedos);
149 private CommentMetadata getComment(long id) {
150 Collection<CommentMetadata> metadata;
152 metadata = managementSupport.getMetadata(id, id, CommentMetadata.class);
153 if (metadata.size() > 0)
154 return metadata.iterator().next();
155 } catch (Throwable t) {
156 Logger.defaultLogError(t);
160 private UndoMetadata getComment4Undo(long id) {
161 Collection<UndoMetadata> metadata;
163 metadata = managementSupport.getMetadata(id, id, UndoMetadata.class);
164 if (metadata.size() > 0)
165 return metadata.iterator().next();
166 } catch (Throwable t) {
167 Logger.defaultLogError(t);
172 public void undo(Operation op)
173 throws DatabaseException {
174 Collection<Operation> ops = new ArrayList<Operation>();
180 public Operation getCurrent() {
181 return session.state.getLastOperation();
185 public int undo(Session session, int count)
186 throws DatabaseException {
187 return undoAndReturnOperations(session, count).size();
191 public List<Operation> undoAndReturnOperations(Session session, int count)
192 throws DatabaseException {
194 return Collections.emptyList();
195 if (!(session instanceof SessionImplDb))
196 return Collections.emptyList();
197 SessionImplDb s = (SessionImplDb)session;
198 return s.graphSession.undoContext.undo(this, count);
202 public List<Operation> redo(Session session, int count)
203 throws DatabaseException {
205 return Collections.emptyList();
206 if (!(session instanceof SessionImplDb))
207 return Collections.emptyList();
208 SessionImplDb s = (SessionImplDb)session;
209 return s.graphSession.undoContext.redo(this, count);
213 public int undoTo(Session session, long changeSet)
214 throws DatabaseException {
215 if (!(session instanceof SessionImplDb) || changeSet < 1)
217 SessionImplDb s = (SessionImplDb)session;
218 long head = s.graphSession.getLastChangeSetId();
219 int SIZE = (int)(head - changeSet);
222 s.graphSession.undoContext.clear();
223 Vector<Operation> ops = new Vector<Operation>(SIZE);
226 for (int i = 0; i<SIZE; ++i) {
228 Operation o = new OperationImpl(id, id);
229 ops.setElementAt(o, i);
235 public int initUndoListFrom(Session session, long changeSet)
236 throws DatabaseException {
237 if (!(session instanceof SessionImplDb) || changeSet < 1)
239 SessionImplDb s = (SessionImplDb)session;
240 long head = s.graphSession.getLastChangeSetId();
241 int SIZE = (int)(head - changeSet + 1);
244 ManagementSupport ms = session.getService(ManagementSupport.class);
245 Collection<CommitMetadata> metadata = ms.getMetadata(changeSet, head, CommitMetadata.class);
246 if (metadata.size() != SIZE)
248 s.graphSession.undoContext.clear();
250 Iterator<CommitMetadata> it = metadata.iterator();
251 long csid = changeSet;
253 for (; csid<SIZE; ++csid) {
254 CommitMetadata md = it.next();
256 if (md.opid != 0 && md.opid != csid)
260 long id = md.opid != 0 ? md.opid : csid;
261 Operation op = new OperationImpl(id, csid);
262 s.graphSession.undoContext.commitOk(op);
264 return (int)(csid - first);
267 public UndoContext getUndoContext(Session session) {
268 if (session instanceof SessionImplSocket) {
269 GraphSession graphSession = ((SessionImplSocket)session).graphSession;
270 return graphSession != null ? graphSession.undoContext : null;
275 public void subscribe(ChangeListener changeListener) {
276 session.graphSession.undoContext.addChangeListener(changeListener);
279 public void cancel(ChangeListener changelistener) {
280 session.graphSession.undoContext.removeChangeListener(changelistener);
284 public void addExternalOperation(WriteGraph graph, ExternalOperation op) {
285 if (!(session instanceof SessionImplDb))
287 SessionImplDb s = (SessionImplDb)session;
288 s.graphSession.undoContext.addExternalOperation(op);