2727import de .danielbechler .diff .path .NodePath ;
2828import de .danielbechler .diff .selector .ElementSelector ;
2929import de .danielbechler .util .Assert ;
30+ import org .slf4j .Logger ;
31+ import org .slf4j .LoggerFactory ;
3032
3133import static de .danielbechler .diff .circular .CircularReferenceDetector .CircularReferenceException ;
3234
3537 */
3638public class DifferDispatcher
3739{
40+ private static final Logger logger = LoggerFactory .getLogger (DifferDispatcher .class );
3841 private final DifferProvider differProvider ;
3942 private final CircularReferenceDetectorFactory circularReferenceDetectorFactory ;
4043 private final CircularReferenceExceptionHandler circularReferenceExceptionHandler ;
4144 private final IsIgnoredResolver isIgnoredResolver ;
4245 private final IsReturnableResolver isReturnableResolver ;
43- private CircularReferenceDetector workingCircularReferenceDetector ;
44- private CircularReferenceDetector baseCircularReferenceDetector ;
46+ CircularReferenceDetector workingCircularReferenceDetector ;
47+ CircularReferenceDetector baseCircularReferenceDetector ;
4548
4649 public DifferDispatcher (final DifferProvider differProvider ,
4750 final CircularReferenceDetectorFactory circularReferenceDetectorFactory ,
@@ -68,30 +71,6 @@ protected final void resetInstanceMemory()
6871 baseCircularReferenceDetector = circularReferenceDetectorFactory .createCircularReferenceDetector ();
6972 }
7073
71- private static DiffNode findNodeMatchingPropertyPath (final DiffNode node , final NodePath nodePath )
72- {
73- if (node == null )
74- {
75- return null ;
76- }
77- if (node .matches (nodePath ))
78- {
79- return node ;
80- }
81- return findNodeMatchingPropertyPath (node .getParentNode (), nodePath );
82- }
83-
84- private static DiffNode newCircularNode (final DiffNode parentNode ,
85- final Instances instances ,
86- final NodePath circleStartPath )
87- {
88- final DiffNode node = new DiffNode (parentNode , instances .getSourceAccessor (), instances .getType ());
89- node .setState (DiffNode .State .CIRCULAR );
90- node .setCircleStartPath (circleStartPath );
91- node .setCircleStartNode (findNodeMatchingPropertyPath (parentNode , circleStartPath ));
92- return node ;
93- }
94-
9574 /**
9675 * Delegates the call to an appropriate {@link Differ}.
9776 *
@@ -137,7 +116,7 @@ private DiffNode compare(final DiffNode parentNode,
137116 private DiffNode compareWithCircularReferenceTracking (final DiffNode parentNode ,
138117 final Instances instances )
139118 {
140- DiffNode node ;
119+ DiffNode node = null ;
141120 try
142121 {
143122 rememberInstances (parentNode , instances );
@@ -147,7 +126,10 @@ private DiffNode compareWithCircularReferenceTracking(final DiffNode parentNode,
147126 }
148127 finally
149128 {
150- forgetInstances (instances );
129+ if (node != null )
130+ {
131+ forgetInstances (parentNode , instances );
132+ }
151133 }
152134 }
153135 catch (final CircularReferenceException e )
@@ -173,8 +155,20 @@ private DiffNode compare(final DiffNode parentNode, final Instances instances)
173155 return differ .compare (parentNode , instances );
174156 }
175157
176- protected void forgetInstances (final Instances instances )
158+ protected void forgetInstances (final DiffNode parentNode , final Instances instances )
177159 {
160+ final NodePath nodePath ;
161+ if (parentNode != null )
162+ {
163+ final NodePath parentPath = parentNode .getPath ();
164+ final ElementSelector elementSelector = instances .getSourceAccessor ().getElementSelector ();
165+ nodePath = NodePath .startBuildingFrom (parentPath ).element (elementSelector ).build ();
166+ }
167+ else
168+ {
169+ nodePath = NodePath .withRoot ();
170+ }
171+ logger .debug ("[ {} ] Forgetting --- WORKING: {} <=> BASE: {}" , nodePath , instances .getWorking (), instances .getBase ());
178172 workingCircularReferenceDetector .remove (instances .getWorking ());
179173 baseCircularReferenceDetector .remove (instances .getBase ());
180174 }
@@ -192,7 +186,49 @@ protected void rememberInstances(final DiffNode parentNode, final Instances inst
192186 {
193187 nodePath = NodePath .withRoot ();
194188 }
189+ logger .debug ("[ {} ] Remembering --- WORKING: {} <=> BASE: {}" , nodePath , instances .getWorking (), instances .getBase ());
190+
191+ transactionalPushToCircularReferenceDetectors (nodePath , instances );
192+ }
193+
194+ private void transactionalPushToCircularReferenceDetectors (final NodePath nodePath , final Instances instances )
195+ {
195196 workingCircularReferenceDetector .push (instances .getWorking (), nodePath );
196- baseCircularReferenceDetector .push (instances .getBase (), nodePath );
197+
198+ // TODO This needs to be solved more elegantly. If the push for one of these detectors fails,
199+ // we need to make sure to revert the push to the other one, if it already happened.
200+ try
201+ {
202+ baseCircularReferenceDetector .push (instances .getBase (), nodePath );
203+ }
204+ catch (final CircularReferenceException e )
205+ {
206+ workingCircularReferenceDetector .remove (instances .getWorking ()); // rollback
207+ throw e ;
208+ }
209+ }
210+
211+ private static DiffNode findNodeMatchingPropertyPath (final DiffNode node , final NodePath nodePath )
212+ {
213+ if (node == null )
214+ {
215+ return null ;
216+ }
217+ if (node .matches (nodePath ))
218+ {
219+ return node ;
220+ }
221+ return findNodeMatchingPropertyPath (node .getParentNode (), nodePath );
222+ }
223+
224+ private static DiffNode newCircularNode (final DiffNode parentNode ,
225+ final Instances instances ,
226+ final NodePath circleStartPath )
227+ {
228+ final DiffNode node = new DiffNode (parentNode , instances .getSourceAccessor (), instances .getType ());
229+ node .setState (DiffNode .State .CIRCULAR );
230+ node .setCircleStartPath (circleStartPath );
231+ node .setCircleStartNode (findNodeMatchingPropertyPath (parentNode , circleStartPath ));
232+ return node ;
197233 }
198234}
0 commit comments