2 Commits

Author SHA1 Message Date
f5067490a3 2 updated 2026-07-06 17:50:41 +02:00
3a442c8890 2 tests 2026-07-06 17:49:11 +02:00
3 changed files with 32 additions and 4 deletions

View File

@@ -195,7 +195,7 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
}
private final java.util.Map<String, String> simplifyCache = new java.util.HashMap<>();
private final java.util.Map<String, Boolean> guardedCache = new java.util.HashMap<>();
private final java.util.Map<java.util.Map.Entry<String, String>, Boolean> guardedCache = new java.util.HashMap<>();
private static final java.util.regex.Pattern SUFFIX_PATTERN = java.util.regex.Pattern.compile("(?i)(.+)(Event|Action|Transition|Command)(s)?$");
private static final java.util.regex.Pattern FQN_PATTERN = java.util.regex.Pattern.compile("^.*\\.([A-Z0-9_]+)$");
@@ -217,7 +217,9 @@ public class TransitionLinkerEnricher implements AnalysisEnricher {
private boolean isGuardedContains(String smEvent, String triggerEvent) {
if (smEvent == null || triggerEvent == null) return false;
String cacheKey = smEvent + "|" + triggerEvent;
// Use a strictly immutable pair to guarantee 100% collision-free caching regardless of string content
java.util.Map.Entry<String, String> cacheKey = new java.util.AbstractMap.SimpleImmutableEntry<>(smEvent, triggerEvent);
if (guardedCache.containsKey(cacheKey)) return guardedCache.get(cacheKey);
boolean result = calculateGuardedContains(smEvent, triggerEvent);

View File

@@ -88,13 +88,14 @@ public class HeuristicEventMatchingEngine implements EventMatchingEngine {
}
private final java.util.Map<String, String> simplifyCache = new java.util.HashMap<>();
private final java.util.Map<String, Boolean> guardedCache = new java.util.HashMap<>();
private final java.util.Map<java.util.Map.Entry<String, String>, Boolean> guardedCache = new java.util.HashMap<>();
private static final java.util.regex.Pattern SUFFIX_PATTERN = java.util.regex.Pattern.compile("(?i)(.+)(Event|Action|Transition|Command)(s)?$");
private static final java.util.regex.Pattern FQN_PATTERN = java.util.regex.Pattern.compile("^.*\\.([A-Z0-9_]+)$");
private boolean isGuardedContains(String smEvent, String triggerEvent) {
if (smEvent == null || triggerEvent == null) return false;
String cacheKey = smEvent + "|" + triggerEvent;
java.util.Map.Entry<String, String> cacheKey = new java.util.AbstractMap.SimpleImmutableEntry<>(smEvent, triggerEvent);
if (guardedCache.containsKey(cacheKey)) return guardedCache.get(cacheKey);
boolean result = calculateGuardedContains(smEvent, triggerEvent);

View File

@@ -248,6 +248,31 @@ class TransitionLinkerEnricherTest {
assertThat(updatedChain.getMatchedTransitions()).isNullOrEmpty();
}
@Test
void shouldExecuteDeterministicallyAndUtilizeInternalCaches() {
Transition t1 = new Transition();
t1.setSourceStates(List.of(State.of("NEW", "NEW")));
t1.setTargetStates(List.of(State.of("PAID", "PAID")));
t1.setEvent(Event.of("PAY", "PAY"));
CallChain chain1 = CallChain.builder().triggerPoint(TriggerPoint.builder().event("PAY").build()).build();
CallChain chain2 = CallChain.builder().triggerPoint(TriggerPoint.builder().event("PAY").build()).build();
CallChain chain3 = CallChain.builder().triggerPoint(TriggerPoint.builder().event("PAY").build()).build();
AnalysisResult result = AnalysisResult.builder()
.transitions(List.of(t1))
.metadata(CodebaseMetadata.builder().callChains(List.of(chain1, chain2, chain3)).build())
.build();
enricher.enrich(result, null, null);
// All 3 identical trigger point chains should be linked seamlessly using the memoization cache.
for (CallChain chain : result.getMetadata().getCallChains()) {
assertThat(chain.getMatchedTransitions()).hasSize(1);
assertThat(chain.getMatchedTransitions().get(0).getEvent()).isEqualTo("PAY");
}
}
@Test
void shouldFilterCrossStateMachineRoutingByVertical() {