]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/UndoRedoSupportImpl.java
Some fixes/cleanup for cluster table size caching logic.
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / UndoRedoSupportImpl.java
1 package fi.vtt.simantics.procore.internal;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Vector;
9
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;
27
28 import fi.vtt.simantics.procore.internal.SessionImplSocket.TaskHelper;
29
30 public class UndoRedoSupportImpl implements UndoRedoSupport {
31     final private boolean DEBUG = SessionImplSocket.DEBUG;
32     final private SessionImplSocket session;
33     final ManagementSupport managementSupport;
34
35     UndoRedoSupportImpl(SessionImplSocket session) {
36         this.session = session;
37         this.managementSupport = session.getService(ManagementSupport.class);
38     }
39
40     @Override
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) {
48             @Override
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);
57                 try {
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) {
66                     if (DEBUG)
67                         e.printStackTrace();
68                     th.throwableSet(e);
69                     th.sema.release();
70                     return;
71                 }
72                 try {
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());
78                     if (null != pum) {
79                         writer.addMetadata(um.add(pum));
80                         um.setTypeAndRange(pum);
81                     }
82                     writer.addMetadata(um.add("Undo operation " + fop.getId() + "."));
83                     Operation ope = fop;
84                     if (ops.size() > 1) {
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() + "."));
89                         ope = lop;
90                     }
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);
95                     }
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) {
105                     if (DEBUG)
106                         e.printStackTrace();
107                     Logger.defaultLogError(e);
108                     th.throwableSet(e);
109                 }
110             }
111         });
112         session.acquire(th.sema, th.writeTraits);
113         th.throwableCheck();
114         long headChangeSetId = session.state.getHeadRevisionId();
115         if (id.get() == headChangeSetId+1)
116             return null; // Empty undo operation;
117
118         final ArrayList<ExternalOperation> externalRedos = new ArrayList<ExternalOperation>();
119         GraphSession.forExternals(ops, new FunctionImpl1<ExternalOperation, Boolean>() {
120
121                 @Override
122                 public Boolean apply(final ExternalOperation op) {
123                         externalRedos.add(new ExternalOperation() {
124
125                                         @Override
126                                         public void undo() {
127                                                 op.redo();
128                                         }
129
130                                         @Override
131                                         public void redo() {
132                                                 op.undo();
133                                         }
134
135                                         @Override
136                                         public boolean isDisposed() {
137                                                 return op.isDisposed();
138                                         }
139
140                         });
141                         return true;
142                 }
143
144         });
145
146         return new OperationImpl(id.get(), id.get(), externalRedos);
147
148     }
149     private CommentMetadata getComment(long id) {
150         Collection<CommentMetadata> metadata;
151         try {
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);
157         }
158         return null;
159     }
160     private UndoMetadata getComment4Undo(long id) {
161         Collection<UndoMetadata> metadata;
162         try {
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);
168         }
169         return null;
170     }
171     @Override
172     public void undo(Operation op)
173     throws DatabaseException {
174         Collection<Operation> ops = new ArrayList<Operation>();
175         ops.add(op);
176         undo(ops);
177     }
178
179     @Override
180     public Operation getCurrent() {
181         return session.state.getLastOperation();
182     }
183
184     @Override
185     public int undo(Session session, int count)
186     throws DatabaseException {
187         return undoAndReturnOperations(session, count).size();
188     }
189
190     @Override
191     public List<Operation> undoAndReturnOperations(Session session, int count)
192     throws DatabaseException {
193         if ( count < 1)
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);
199     }
200
201     @Override
202     public List<Operation> redo(Session session, int count)
203     throws DatabaseException {
204         if ( count < 1)
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);
210     }
211
212     @Override
213     public int undoTo(Session session, long changeSet)
214         throws DatabaseException {
215         if (!(session instanceof SessionImplDb) || changeSet < 1)
216             return 0;
217         SessionImplDb s = (SessionImplDb)session;
218         long head = s.graphSession.getLastChangeSetId();
219         int SIZE = (int)(head - changeSet);
220         if (SIZE < 1)
221             return 0;
222         s.graphSession.undoContext.clear();
223         Vector<Operation> ops = new Vector<Operation>(SIZE);
224         ops.setSize(SIZE);
225         long id = changeSet;
226         for (int i = 0; i<SIZE; ++i) {
227             ++id;
228             Operation o = new OperationImpl(id, id);
229             ops.setElementAt(o, i);
230         }
231         undo(ops);
232         return SIZE;
233     }
234     @Override
235     public int initUndoListFrom(Session session, long changeSet)
236         throws DatabaseException {
237         if (!(session instanceof SessionImplDb) || changeSet < 1)
238             return 0;
239         SessionImplDb s = (SessionImplDb)session;
240         long head = s.graphSession.getLastChangeSetId();
241         int SIZE = (int)(head - changeSet + 1);
242         if (SIZE < 1)
243             return 0;
244         ManagementSupport ms = session.getService(ManagementSupport.class);
245         Collection<CommitMetadata> metadata = ms.getMetadata(changeSet, head, CommitMetadata.class);
246         if (metadata.size() != SIZE)
247             return 0;
248         s.graphSession.undoContext.clear();
249         long first = 0;
250         Iterator<CommitMetadata> it = metadata.iterator();
251         long csid = changeSet;
252         SIZE += csid;
253         for (; csid<SIZE; ++csid) {
254             CommitMetadata md = it.next();
255             if (first == 0) {
256                 if (md.opid != 0 && md.opid != csid)
257                     continue;
258                 first = csid;
259             }
260             long id = md.opid != 0 ? md.opid : csid;
261             Operation op = new OperationImpl(id, csid);
262             s.graphSession.undoContext.commitOk(op);
263         }
264         return (int)(csid - first);
265     }
266     @Override
267     public UndoContext getUndoContext(Session session) {
268         if (session instanceof SessionImplSocket) {
269             GraphSession graphSession = ((SessionImplSocket)session).graphSession;
270             return graphSession != null ? graphSession.undoContext : null;
271         }
272         return null;
273     }
274     @Override
275     public void subscribe(ChangeListener changeListener) {
276         session.graphSession.undoContext.addChangeListener(changeListener);
277     }
278     @Override
279     public void cancel(ChangeListener changelistener) {
280         session.graphSession.undoContext.removeChangeListener(changelistener);
281     }
282
283     @Override
284     public void addExternalOperation(WriteGraph graph, ExternalOperation op) {
285         if (!(session instanceof SessionImplDb))
286             return;
287         SessionImplDb s = (SessionImplDb)session;
288         s.graphSession.undoContext.addExternalOperation(op);
289     }
290
291 }