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) {
49 public void run0(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().propagateChangesInQueryCache(writer);
97 session.fireMetadataListeners(writer, cs);
98 session.getQueryProvider2().listening.fireListeners(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);
114 session.acquire(th.sema, th.writeTraits);
116 long headChangeSetId = session.state.getHeadRevisionId();
117 if (id.get() == headChangeSetId+1)
118 return null; // Empty undo operation;
120 final ArrayList<ExternalOperation> externalRedos = new ArrayList<ExternalOperation>();
121 GraphSession.forExternals(ops, new FunctionImpl1<ExternalOperation, Boolean>() {
124 public Boolean apply(final ExternalOperation op) {
125 externalRedos.add(new ExternalOperation() {
138 public boolean isDisposed() {
139 return op.isDisposed();
148 return new OperationImpl(id.get(), id.get(), externalRedos);
151 private CommentMetadata getComment(long id) {
152 Collection<CommentMetadata> metadata;
154 metadata = managementSupport.getMetadata(id, id, CommentMetadata.class);
155 if (metadata.size() > 0)
156 return metadata.iterator().next();
157 } catch (Throwable t) {
158 Logger.defaultLogError(t);
162 private UndoMetadata getComment4Undo(long id) {
163 Collection<UndoMetadata> metadata;
165 metadata = managementSupport.getMetadata(id, id, UndoMetadata.class);
166 if (metadata.size() > 0)
167 return metadata.iterator().next();
168 } catch (Throwable t) {
169 Logger.defaultLogError(t);
174 public void undo(Operation op)
175 throws DatabaseException {
176 Collection<Operation> ops = new ArrayList<Operation>();
182 public Operation getCurrent() {
183 return session.state.getLastOperation();
187 public int undo(Session session, int count)
188 throws DatabaseException {
189 return undoAndReturnOperations(session, count).size();
193 public List<Operation> undoAndReturnOperations(Session session, int count)
194 throws DatabaseException {
196 return Collections.emptyList();
197 if (!(session instanceof SessionImplDb))
198 return Collections.emptyList();
199 SessionImplDb s = (SessionImplDb)session;
200 return s.graphSession.undoContext.undo(this, count);
204 public List<Operation> redo(Session session, int count)
205 throws DatabaseException {
207 return Collections.emptyList();
208 if (!(session instanceof SessionImplDb))
209 return Collections.emptyList();
210 SessionImplDb s = (SessionImplDb)session;
211 return s.graphSession.undoContext.redo(this, count);
215 public int undoTo(Session session, long changeSet)
216 throws DatabaseException {
217 if (!(session instanceof SessionImplDb) || changeSet < 1)
219 SessionImplDb s = (SessionImplDb)session;
220 long head = s.graphSession.getLastChangeSetId();
221 int SIZE = (int)(head - changeSet);
224 s.graphSession.undoContext.clear();
225 Vector<Operation> ops = new Vector<Operation>(SIZE);
228 for (int i = 0; i<SIZE; ++i) {
230 Operation o = new OperationImpl(id, id);
231 ops.setElementAt(o, i);
237 public int initUndoListFrom(Session session, long changeSet)
238 throws DatabaseException {
239 if (!(session instanceof SessionImplDb) || changeSet < 1)
241 SessionImplDb s = (SessionImplDb)session;
242 long head = s.graphSession.getLastChangeSetId();
243 int SIZE = (int)(head - changeSet + 1);
246 ManagementSupport ms = session.getService(ManagementSupport.class);
247 Collection<CommitMetadata> metadata = ms.getMetadata(changeSet, head, CommitMetadata.class);
248 if (metadata.size() != SIZE)
250 s.graphSession.undoContext.clear();
252 Iterator<CommitMetadata> it = metadata.iterator();
253 long csid = changeSet;
255 for (; csid<SIZE; ++csid) {
256 CommitMetadata md = it.next();
258 if (md.opid != 0 && md.opid != csid)
262 long id = md.opid != 0 ? md.opid : csid;
263 Operation op = new OperationImpl(id, csid);
264 s.graphSession.undoContext.commitOk(op);
266 return (int)(csid - first);
269 public UndoContext getUndoContext(Session session) {
270 if (session instanceof SessionImplSocket) {
271 GraphSession graphSession = ((SessionImplSocket)session).graphSession;
272 return graphSession != null ? graphSession.undoContext : null;
277 public void subscribe(ChangeListener changeListener) {
278 session.graphSession.undoContext.addChangeListener(changeListener);
281 public void cancel(ChangeListener changelistener) {
282 session.graphSession.undoContext.removeChangeListener(changelistener);
286 public void addExternalOperation(WriteGraph graph, ExternalOperation op) {
287 if (!(session instanceof SessionImplDb))
289 SessionImplDb s = (SessionImplDb)session;
290 s.graphSession.undoContext.addExternalOperation(op);