66import java .util .IdentityHashMap ;
77import java .util .LinkedHashSet ;
88import java .util .List ;
9- import java .util .Map ;
109import java .util .Objects ;
1110import java .util .Set ;
1211import java .util .function .Consumer ;
2423import ai .timefold .solver .core .config .solver .EnvironmentMode ;
2524import ai .timefold .solver .core .impl .domain .entity .descriptor .EntityDescriptor ;
2625import ai .timefold .solver .core .impl .domain .lookup .LookUpManager ;
27- import ai .timefold .solver .core .impl .domain .solution .ConstraintWeightSupplier ;
2826import ai .timefold .solver .core .impl .domain .solution .descriptor .SolutionDescriptor ;
2927import ai .timefold .solver .core .impl .domain .variable .ListVariableStateSupply ;
3028import ai .timefold .solver .core .impl .domain .variable .descriptor .ListVariableDescriptor ;
@@ -312,17 +310,17 @@ protected void setWorkingEntityListDirty() {
312310 @ Override
313311 public Solution_ cloneSolution (Solution_ originalSolution ) {
314312 SolutionDescriptor <Solution_ > solutionDescriptor = getSolutionDescriptor ();
315- Score_ originalScore = solutionDescriptor .getScore (originalSolution );
316- Solution_ cloneSolution = solutionDescriptor .getSolutionCloner ().cloneSolution (originalSolution );
317- Score_ cloneScore = solutionDescriptor .getScore (cloneSolution );
313+ var originalScore = solutionDescriptor .getScore (originalSolution );
314+ var cloneSolution = solutionDescriptor .getSolutionCloner ().cloneSolution (originalSolution );
315+ var cloneScore = solutionDescriptor .getScore (cloneSolution );
318316 if (scoreDirectorFactory .isAssertClonedSolution ()) {
319317 if (!Objects .equals (originalScore , cloneScore )) {
320318 throw new CloningCorruptionException ("""
321319 Cloning corruption: the original's score (%s) is different from the clone's score (%s).
322320 Check the %s."""
323321 .formatted (originalScore , cloneScore , SolutionCloner .class .getSimpleName ()));
324322 }
325- Map < Object , Object > originalEntityMap = new IdentityHashMap <>();
323+ var originalEntityMap = new IdentityHashMap <>();
326324 solutionDescriptor .visitAllEntities (originalSolution ,
327325 originalEntity -> originalEntityMap .put (originalEntity , null ));
328326 solutionDescriptor .visitAllEntities (cloneSolution , cloneEntity -> {
@@ -343,6 +341,16 @@ public void triggerVariableListeners() {
343341 variableListenerSupport .triggerVariableListenersInNotificationQueues ();
344342 }
345343
344+ /**
345+ * This function clears all listener events that have been generated without triggering any of them.
346+ * Using this method requires caution because clearing the event queue can lead to inconsistent states.
347+ * This occurs when the shadow variables are not updated,
348+ * causing constraints reliant on these variables to be inaccurately evaluated.
349+ */
350+ protected void clearVariableListenerEvents () {
351+ variableListenerSupport .clearAllVariableListenerEvents ();
352+ }
353+
346354 @ Override
347355 public void forceTriggerVariableListeners () {
348356 variableListenerSupport .forceTriggerAllVariableListeners (getWorkingSolution ());
@@ -560,9 +568,9 @@ public void afterProblemPropertyChanged(Object problemFactOrEntity) {
560568 @ Override
561569 public void beforeProblemFactRemoved (Object problemFact ) {
562570 if (isConstraintConfiguration (problemFact )) {
563- throw new IllegalStateException ("Attempted to remove constraint configuration (" + problemFact +
564- ") from solution (" + workingSolution + "). \n " +
565- " Maybe use before/afterProblemPropertyChanged(...) instead." );
571+ throw new IllegalStateException ("""
572+ Attempted to remove constraint configuration (%s) from solution (%s).
573+ Maybe use before/afterProblemPropertyChanged(...) instead.""" . formatted ( problemFact , workingSolution ) );
566574 }
567575 }
568576
@@ -580,17 +588,19 @@ public void afterProblemFactRemoved(Object problemFact) {
580588 @ Override
581589 public <E > @ Nullable E lookUpWorkingObject (@ Nullable E externalObject ) {
582590 if (!lookUpEnabled ) {
583- throw new IllegalStateException ("When lookUpEnabled (" + lookUpEnabled
584- + ") is disabled in the constructor, this method should not be called." );
591+ throw new IllegalStateException (
592+ "When lookUpEnabled (%s) is disabled in the constructor, this method should not be called."
593+ .formatted (lookUpEnabled ));
585594 }
586595 return lookUpManager .lookUpWorkingObject (externalObject );
587596 }
588597
589598 @ Override
590599 public <E > @ Nullable E lookUpWorkingObjectOrReturnNull (@ Nullable E externalObject ) {
591600 if (!lookUpEnabled ) {
592- throw new IllegalStateException ("When lookUpEnabled (" + lookUpEnabled
593- + ") is disabled in the constructor, this method should not be called." );
601+ throw new IllegalStateException (
602+ "When lookUpEnabled (%s) is disabled in the constructor, this method should not be called."
603+ .formatted (lookUpEnabled ));
594604 }
595605 return lookUpManager .lookUpWorkingObjectOrReturnNull (externalObject );
596606 }
@@ -601,7 +611,7 @@ public void afterProblemFactRemoved(Object problemFact) {
601611
602612 @ Override
603613 public void assertExpectedWorkingScore (Score_ expectedWorkingScore , Object completedAction ) {
604- Score_ workingScore = calculateScore ();
614+ var workingScore = calculateScore ();
605615 if (!expectedWorkingScore .equals (workingScore )) {
606616 throw new ScoreCorruptionException ("""
607617 Score corruption (%s): the expectedWorkingScore (%s) is not the workingScore (%s) \
@@ -613,15 +623,15 @@ after completedAction (%s)."""
613623
614624 @ Override
615625 public void assertShadowVariablesAreNotStale (Score_ expectedWorkingScore , Object completedAction ) {
616- String violationMessage = variableListenerSupport .createShadowVariablesViolationMessage ();
626+ var violationMessage = variableListenerSupport .createShadowVariablesViolationMessage ();
617627 if (violationMessage != null ) {
618628 throw new VariableCorruptionException ("""
619629 %s corruption after completedAction (%s):
620630 %s"""
621631 .formatted (VariableListener .class .getSimpleName (), completedAction , violationMessage ));
622632 }
623633
624- Score_ workingScore = calculateScore ();
634+ var workingScore = calculateScore ();
625635 if (!expectedWorkingScore .equals (workingScore )) {
626636 assertWorkingScoreFromScratch (workingScore ,
627637 "assertShadowVariablesAreNotStale(" + expectedWorkingScore + ", " + completedAction + ")" );
@@ -642,8 +652,8 @@ public void assertShadowVariablesAreNotStale(Score_ expectedWorkingScore, Object
642652 * @return never null
643653 */
644654 protected String buildShadowVariableAnalysis (boolean predicted ) {
645- String violationMessage = variableListenerSupport .createShadowVariablesViolationMessage ();
646- String workingLabel = predicted ? "working" : "corrupted" ;
655+ var violationMessage = variableListenerSupport .createShadowVariablesViolationMessage ();
656+ var workingLabel = predicted ? "working" : "corrupted" ;
647657 if (violationMessage == null ) {
648658 return """
649659 Shadow variable corruption in the %s scoreDirector:
@@ -894,8 +904,8 @@ private void iterateAndAddIfFound(List<MatchAnalysis<Score_>> referenceList, Lis
894904 }
895905
896906 protected boolean isConstraintConfiguration (Object problemFactOrEntity ) {
897- SolutionDescriptor < Solution_ > solutionDescriptor = scoreDirectorFactory .getSolutionDescriptor ();
898- ConstraintWeightSupplier < Solution_ , Score_ > constraintWeightSupplier = solutionDescriptor .getConstraintWeightSupplier ();
907+ var solutionDescriptor = scoreDirectorFactory .getSolutionDescriptor ();
908+ var constraintWeightSupplier = solutionDescriptor .getConstraintWeightSupplier ();
899909 if (constraintWeightSupplier == null ) {
900910 return false ;
901911 }
0 commit comments