in src/main/software/amazon/event/ruler/GenericMachine.java [275:371]
private Set<SubRuleContext> deleteStep(final NameState state,
final List<String> keys,
final int keyIndex,
final Map<String, List<Patterns>> patterns,
final T ruleName,
final List<String> deletedKeys,
final Set<SubRuleContext> candidateSubRuleIds) {
final Set<SubRuleContext> deletedSubRuleIds = new HashSet<>();
final String key = keys.get(keyIndex);
ByteMachine byteMachine = state.getTransitionOn(key);
NameMatcher<NameState> nameMatcher = state.getKeyTransitionOn(key);
// matchers are null, we have nothing to delete.
if (byteMachine == null && nameMatcher == null) {
return deletedSubRuleIds;
}
for (Patterns pattern : patterns.get(key)) {
NameState nextNameState = null;
if (isNamePattern(pattern)) {
if (nameMatcher != null) {
nextNameState = nameMatcher.findPattern(pattern);
}
} else {
if (byteMachine != null) {
nextNameState = byteMachine.findPattern(pattern);
}
}
if (nextNameState != null) {
// If this was the last step, then reaching the last state means the rule matched, and we should delete
// the rule from the next NameState.
final int nextKeyIndex = keyIndex + 1;
boolean isTerminal = nextKeyIndex == keys.size();
// Trim the candidate sub-rule ID set to contain only the sub-rule IDs present in the next NameState.
Set<SubRuleContext> nextNameStateSubRuleIds = isTerminal ?
nextNameState.getTerminalSubRuleIdsForPattern(pattern) :
nextNameState.getNonTerminalSubRuleIdsForPattern(pattern);
// If no sub-rule IDs are found for next NameState, then we have no candidates, and will return below
// without further recursion through the keys.
if (nextNameStateSubRuleIds == null) {
candidateSubRuleIds.clear();
// If candidate set is empty, we are at first NameState, so initialize to next NameState's sub-rule IDs.
// When initializing, ensure that sub-rule IDs match the provided rule name for deletion.
} else if (candidateSubRuleIds.isEmpty()) {
for (SubRuleContext nextNameStateSubRuleId : nextNameStateSubRuleIds) {
if (Objects.equals(ruleName,
nextNameStateSubRuleId.getRuleName())) {
candidateSubRuleIds.add(nextNameStateSubRuleId);
}
}
// Have already initialized candidate set. Just retain the candidates present in the next NameState.
} else {
candidateSubRuleIds.retainAll(nextNameStateSubRuleIds);
}
if (isTerminal) {
for (SubRuleContext candidateSubRuleId : candidateSubRuleIds) {
if (nextNameState.deleteSubRule(
candidateSubRuleId.getRuleName(), candidateSubRuleId,
pattern, true)) {
deletedSubRuleIds.add(candidateSubRuleId);
// Only delete the pattern if the pattern does not transition to the next NameState.
if (!doesNameStateContainPattern(nextNameState, pattern) &&
deletePattern(state, key, pattern)) {
deletedKeys.add(key);
state.removeNextNameState(key);
}
}
}
} else {
if (candidateSubRuleIds.isEmpty()) {
return deletedSubRuleIds;
}
deletedSubRuleIds.addAll(deleteStep(nextNameState, keys, nextKeyIndex, patterns, ruleName,
deletedKeys, new HashSet<>(candidateSubRuleIds)));
for (SubRuleContext deletedSubRuleId : deletedSubRuleIds) {
nextNameState.deleteSubRule(deletedSubRuleId.getRuleName(),
deletedSubRuleId, pattern, false);
}
// Unwinding the key recursion, so we aren't on a rule match. Only delete the pattern if the pattern
// does not transition to the next NameState.
if (!doesNameStateContainPattern(nextNameState, pattern) && deletePattern(state, key, pattern)) {
deletedKeys.add(key);
state.removeNextNameState(key);
}
}
}
}
return deletedSubRuleIds;
}