1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.treetank.service.xml.diff;
29
30 import static org.treetank.node.IConstants.ELEMENT;
31 import static org.treetank.node.IConstants.ROOT;
32 import static org.treetank.node.IConstants.ROOT_NODE;
33 import static org.treetank.node.IConstants.TEXT;
34
35 import javax.xml.namespace.QName;
36
37 import org.treetank.access.NodeReadTrx;
38 import org.treetank.access.NodeWriteTrx.HashKind;
39 import org.treetank.api.INodeReadTrx;
40 import org.treetank.exception.TTException;
41 import org.treetank.exception.TTIOException;
42 import org.treetank.node.interfaces.IStructNode;
43 import org.treetank.service.xml.diff.DiffFactory.Builder;
44 import org.treetank.service.xml.diff.DiffFactory.EDiff;
45 import org.treetank.service.xml.diff.DiffFactory.EDiffOptimized;
46
47
48
49
50
51
52
53 abstract class AbsDiff extends AbsDiffObservable {
54
55
56 enum EFireDiff {
57
58 TRUE,
59
60
61 FALSE
62 }
63
64
65 enum ERevision {
66
67
68 OLD,
69
70
71 NEW;
72 }
73
74
75
76
77
78
79 transient HashKind mHashKind;
80
81
82
83
84
85
86 private transient EDiff mDiff;
87
88
89 private transient EDiffOptimized mDiffKind;
90
91
92 private transient DepthCounter mDepth;
93
94
95 private transient long mRootKey;
96
97
98
99
100
101
102
103
104
105 AbsDiff(final Builder paramBuilder) throws TTException {
106 assert paramBuilder != null;
107
108 mDiffKind = paramBuilder.mKind;
109 synchronized (paramBuilder.mSession) {
110 mNewRtx = new NodeReadTrx(paramBuilder.mSession.beginBucketRtx(paramBuilder.mNewRev));
111 mOldRtx = new NodeReadTrx(paramBuilder.mSession.beginBucketRtx(paramBuilder.mOldRev));
112 mHashKind = HashKind.Postorder;
113 }
114 mNewRtx.moveTo(paramBuilder.mKey);
115 mOldRtx.moveTo(paramBuilder.mKey);
116 mRootKey = paramBuilder.mKey;
117
118 synchronized (paramBuilder.mObservers) {
119 for (final IDiffObserver observer : paramBuilder.mObservers) {
120 addObserver(observer);
121 }
122 }
123 mDiff = EDiff.SAME;
124 mDiffKind = paramBuilder.mKind;
125 mDepth = new DepthCounter(paramBuilder.mNewDepth, paramBuilder.mOldDepth);
126
127
128
129 }
130
131
132
133
134
135
136
137 void diffMovement() throws TTException {
138 assert mHashKind != null;
139 assert mNewRtx != null;
140 assert mOldRtx != null;
141 assert mDiff != null;
142 assert mDiffKind != null;
143
144
145 if (mNewRtx.getNode().getKind() != ROOT) {
146 if (mHashKind == HashKind.None || mDiffKind == EDiffOptimized.NO) {
147 mDiff = diff(mNewRtx, mOldRtx, mDepth, EFireDiff.TRUE);
148 } else {
149 mDiff = optimizedDiff(mNewRtx, mOldRtx, mDepth, EFireDiff.TRUE);
150 }
151 }
152
153
154 while ((mOldRtx.getNode().getKind() != ROOT && mDiff == EDiff.DELETED)
155 || moveCursor(mNewRtx, ERevision.NEW)) {
156 if (mDiff != EDiff.INSERTED) {
157 moveCursor(mOldRtx, ERevision.OLD);
158 }
159
160 if (mNewRtx.getNode().getKind() != ROOT || mOldRtx.getNode().getKind() != ROOT) {
161 if (mHashKind == HashKind.None || mDiffKind == EDiffOptimized.NO) {
162 mDiff = diff(mNewRtx, mOldRtx, mDepth, EFireDiff.TRUE);
163 } else {
164 mDiff = optimizedDiff(mNewRtx, mOldRtx, mDepth, EFireDiff.TRUE);
165 }
166 }
167 }
168
169
170 if (mOldRtx.getNode().getKind() != ROOT) {
171
172
173 while (mDiff == EDiff.INSERTED || moveCursor(mOldRtx, ERevision.OLD)) {
174 if (mHashKind == HashKind.None || mDiffKind == EDiffOptimized.NO) {
175 mDiff = diff(mNewRtx, mOldRtx, mDepth, EFireDiff.TRUE);
176 } else {
177 mDiff = optimizedDiff(mNewRtx, mOldRtx, mDepth, EFireDiff.TRUE);
178 }
179 }
180 }
181
182 done();
183 }
184
185
186
187
188
189
190
191
192
193
194
195 boolean moveCursor(final INodeReadTrx paramRtx, final ERevision paramRevision) throws TTIOException {
196 assert paramRtx != null;
197
198 boolean moved = false;
199
200 final IStructNode node = ((IStructNode)paramRtx.getNode());
201 if (node.hasFirstChild()) {
202 if (node.getKind() != ROOT && mDiffKind == EDiffOptimized.HASHED && mHashKind != HashKind.None
203 && (mDiff == EDiff.SAMEHASH || mDiff == EDiff.DELETED)) {
204 moved = paramRtx.moveTo(((IStructNode)paramRtx.getNode()).getRightSiblingKey());
205
206 if (!moved) {
207 moved = moveToFollowingNode(paramRtx, paramRevision);
208 }
209 } else {
210 moved = paramRtx.moveTo(((IStructNode)paramRtx.getNode()).getFirstChildKey());
211 if (moved) {
212 switch (paramRevision) {
213 case NEW:
214 mDepth.incrementNewDepth();
215 break;
216 case OLD:
217 mDepth.incrementOldDepth();
218 break;
219 }
220 }
221 }
222 } else if (node.hasRightSibling()) {
223 if (paramRtx.getNode().getDataKey() == mRootKey) {
224 paramRtx.moveTo(ROOT_NODE);
225 } else {
226 moved = paramRtx.moveTo(((IStructNode)paramRtx.getNode()).getRightSiblingKey());
227 }
228 } else {
229 moved = moveToFollowingNode(paramRtx, paramRevision);
230 }
231
232 return moved;
233 }
234
235
236
237
238
239
240
241
242
243
244
245 private boolean moveToFollowingNode(final INodeReadTrx paramRtx, final ERevision paramRevision)
246 throws TTIOException {
247 boolean moved = false;
248 while (!((IStructNode)paramRtx.getNode()).hasRightSibling()
249 && ((IStructNode)paramRtx.getNode()).hasParent() && paramRtx.getNode().getDataKey() != mRootKey) {
250 moved = paramRtx.moveTo(paramRtx.getNode().getParentKey());
251 if (moved) {
252 switch (paramRevision) {
253 case NEW:
254 mDepth.decrementNewDepth();
255 break;
256 case OLD:
257 mDepth.decrementOldDepth();
258 break;
259 }
260 }
261 }
262
263 if (paramRtx.getNode().getDataKey() == mRootKey) {
264 paramRtx.moveTo(ROOT_NODE);
265 }
266
267 moved = paramRtx.moveTo(((IStructNode)paramRtx.getNode()).getRightSiblingKey());
268 return moved;
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 EDiff diff(final INodeReadTrx paramNewRtx, final INodeReadTrx paramOldRtx, final DepthCounter paramDepth,
287 final EFireDiff paramFireDiff) throws TTIOException {
288 assert paramNewRtx != null;
289 assert paramOldRtx != null;
290 assert paramDepth != null;
291
292 EDiff diff = EDiff.SAME;
293
294
295 switch (paramNewRtx.getNode().getKind()) {
296 case ROOT:
297 case TEXT:
298 case ELEMENT:
299 if (!checkNodes(paramNewRtx, paramOldRtx)) {
300 diff = diffAlgorithm(paramNewRtx, paramOldRtx, paramDepth);
301 }
302 break;
303 default:
304
305 }
306
307 if (paramFireDiff == EFireDiff.TRUE) {
308 fireDiff(diff, ((IStructNode)paramNewRtx.getNode()), ((IStructNode)paramOldRtx.getNode()),
309 new DiffDepth(paramDepth.getNewDepth(), paramDepth.getOldDepth()));
310 }
311 return diff;
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 EDiff optimizedDiff(final INodeReadTrx paramNewRtx, final INodeReadTrx paramOldRtx,
330 final DepthCounter paramDepth, final EFireDiff paramFireDiff) throws TTIOException {
331 assert paramNewRtx != null;
332 assert paramOldRtx != null;
333 assert paramDepth != null;
334
335 EDiff diff = EDiff.SAMEHASH;
336
337
338 switch (paramNewRtx.getNode().getKind()) {
339 case ROOT:
340 case TEXT:
341 case ELEMENT:
342 if (paramNewRtx.getNode().getDataKey() != paramOldRtx.getNode().getDataKey()
343 || paramNewRtx.getNode().getHash() != paramOldRtx.getNode().getHash()) {
344
345 if (checkNodes(paramNewRtx, paramOldRtx)) {
346 diff = EDiff.SAME;
347 } else {
348 diff = diffAlgorithm(paramNewRtx, paramOldRtx, paramDepth);
349 }
350 }
351 break;
352 default:
353
354 }
355
356 if (paramFireDiff == EFireDiff.TRUE) {
357 if (diff == EDiff.SAMEHASH) {
358 fireDiff(EDiff.SAME, ((IStructNode)paramNewRtx.getNode()), ((IStructNode)paramOldRtx
359 .getNode()), new DiffDepth(paramDepth.getNewDepth(), paramDepth.getOldDepth()));
360 } else {
361 fireDiff(diff, ((IStructNode)paramNewRtx.getNode()), ((IStructNode)paramOldRtx.getNode()),
362 new DiffDepth(paramDepth.getNewDepth(), paramDepth.getOldDepth()));
363 }
364 }
365 return diff;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 private EDiff diffAlgorithm(final INodeReadTrx paramNewRtx, final INodeReadTrx paramOldRtx,
382 final DepthCounter paramDepth) throws TTIOException {
383 EDiff diff = null;
384
385
386 if (paramDepth.getOldDepth() > paramDepth.getNewDepth()) {
387 diff = EDiff.DELETED;
388 } else if (checkUpdate(paramNewRtx, paramOldRtx)) {
389
390 diff = EDiff.UPDATED;
391 } else {
392
393 EFoundEqualNode found = EFoundEqualNode.FALSE;
394 final long key = paramOldRtx.getNode().getDataKey();
395
396 while (((IStructNode)paramOldRtx.getNode()).hasRightSibling()
397 && paramOldRtx.moveTo(((IStructNode)paramOldRtx.getNode()).getRightSiblingKey())
398 && found == EFoundEqualNode.FALSE) {
399 if (checkNodes(paramNewRtx, paramOldRtx)) {
400 found = EFoundEqualNode.TRUE;
401 }
402 }
403
404 paramOldRtx.moveTo(key);
405 diff = found.kindOfDiff();
406 }
407
408 assert diff != null;
409 return diff;
410 }
411
412
413
414
415
416
417
418
419
420
421
422 boolean checkName(final INodeReadTrx paramNewRtx, final INodeReadTrx paramOldRtx) {
423 assert paramNewRtx != null;
424 assert paramOldRtx != null;
425 boolean found = false;
426 if (paramNewRtx.getNode().getKind() == paramOldRtx.getNode().getKind()) {
427 switch (paramNewRtx.getNode().getKind()) {
428 case ELEMENT:
429 if (paramNewRtx.getQNameOfCurrentNode().equals(paramOldRtx.getQNameOfCurrentNode())) {
430 found = true;
431 }
432 break;
433 case TEXT:
434 if (paramNewRtx.getValueOfCurrentNode().equals(paramOldRtx.getValueOfCurrentNode())) {
435 found = true;
436 }
437 break;
438 default:
439 }
440 }
441 return found;
442 }
443
444
445
446
447
448
449
450
451
452
453 abstract boolean checkNodes(final INodeReadTrx paramNewRtx, final INodeReadTrx paramOldRtx)
454 throws TTIOException;
455
456
457
458
459
460
461
462
463
464
465
466 boolean checkUpdate(final INodeReadTrx paramNewRtx, final INodeReadTrx paramOldRtx) throws TTIOException {
467 assert paramNewRtx != null;
468 assert paramOldRtx != null;
469 boolean updated = false;
470 final long newKey = paramNewRtx.getNode().getDataKey();
471 boolean movedNewRtx = paramNewRtx.moveTo(((IStructNode)paramNewRtx.getNode()).getRightSiblingKey());
472 final long oldKey = paramOldRtx.getNode().getDataKey();
473 boolean movedOldRtx = paramOldRtx.moveTo(((IStructNode)paramOldRtx.getNode()).getRightSiblingKey());
474 if (movedNewRtx && movedOldRtx && checkNodes(paramNewRtx, paramOldRtx)) {
475 updated = true;
476 } else if (!movedNewRtx && !movedOldRtx) {
477 movedNewRtx = paramNewRtx.moveTo(paramNewRtx.getNode().getParentKey());
478 movedOldRtx = paramOldRtx.moveTo(paramOldRtx.getNode().getParentKey());
479
480 if (movedNewRtx && movedOldRtx && checkNodes(paramNewRtx, paramOldRtx)) {
481 updated = true;
482 }
483 }
484 paramNewRtx.moveTo(newKey);
485 paramOldRtx.moveTo(oldKey);
486 if (!updated) {
487 updated = paramNewRtx.getNode().getDataKey() == paramOldRtx.getNode().getDataKey();
488 }
489 return updated;
490 }
491 }