3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.qualityprofile.builtin;
22 import com.google.common.base.Splitter;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Date;
26 import java.util.List;
28 import java.util.Objects;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32 import javax.annotation.CheckForNull;
33 import javax.annotation.Nullable;
34 import org.apache.commons.lang3.StringUtils;
35 import org.sonar.api.config.Configuration;
36 import org.sonar.api.rule.RuleStatus;
37 import org.sonar.api.server.ServerSide;
38 import org.sonar.api.server.rule.RuleParamType;
39 import org.sonar.api.utils.System2;
40 import org.sonar.core.config.CorePropertyDefinitions;
41 import org.sonar.core.platform.SonarQubeVersion;
42 import org.sonar.db.DbClient;
43 import org.sonar.db.DbSession;
44 import org.sonar.db.qualityprofile.ActiveRuleDao;
45 import org.sonar.db.qualityprofile.ActiveRuleDto;
46 import org.sonar.db.qualityprofile.ActiveRuleKey;
47 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
48 import org.sonar.db.qualityprofile.OrgQProfileDto;
49 import org.sonar.db.qualityprofile.QProfileChangeDto;
50 import org.sonar.db.qualityprofile.QProfileDto;
51 import org.sonar.db.qualityprofile.RulesProfileDto;
52 import org.sonar.db.rule.RuleDto;
53 import org.sonar.db.rule.RuleParamDto;
54 import org.sonar.server.qualityprofile.ActiveRuleChange;
55 import org.sonar.server.qualityprofile.ActiveRuleInheritance;
56 import org.sonar.server.qualityprofile.RuleActivation;
57 import org.sonar.server.qualityprofile.builtin.RuleActivationContext.ActiveRuleWrapper;
58 import org.sonar.server.qualityprofile.builtin.RuleActivationContext.RuleWrapper;
59 import org.sonar.server.user.UserSession;
60 import org.sonar.server.util.TypeValidations;
62 import static com.google.common.base.Preconditions.checkArgument;
63 import static java.lang.Boolean.TRUE;
64 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
67 * Activation and deactivation of rules in Quality profiles
70 public class RuleActivator {
72 private final System2 system2;
73 private final DbClient db;
74 private final TypeValidations typeValidations;
75 private final UserSession userSession;
76 private final Configuration configuration;
77 private final SonarQubeVersion sonarQubeVersion;
79 public RuleActivator(System2 system2, DbClient db, TypeValidations typeValidations, UserSession userSession,
80 Configuration configuration, SonarQubeVersion sonarQubeVersion) {
81 this.system2 = system2;
83 this.typeValidations = typeValidations;
84 this.userSession = userSession;
85 this.configuration = configuration;
86 this.sonarQubeVersion = sonarQubeVersion;
89 public List<ActiveRuleChange> activate(DbSession dbSession, Collection<RuleActivation> activations, RuleActivationContext context) {
90 return activations.stream().map(a -> activate(dbSession, a, context))
91 .flatMap(List::stream)
95 public List<ActiveRuleChange> activate(DbSession dbSession, RuleActivation activation, RuleActivationContext context) {
96 context.reset(activation.getRuleUuid());
97 return doActivateRecursively(dbSession, activation, context);
100 private List<ActiveRuleChange> doActivateRecursively(DbSession dbSession, RuleActivation activation, RuleActivationContext context) {
101 RuleDto rule = context.getRule().get();
102 checkRequest(RuleStatus.REMOVED != rule.getStatus(), "Rule was removed: %s", rule.getKey());
103 checkRequest(!rule.isTemplate(), "Rule template can't be activated on a Quality profile: %s", rule.getKey());
104 checkRequest(context.getRulesProfile().getLanguage().equals(rule.getLanguage()),
105 "%s rule %s cannot be activated on %s profile %s", rule.getLanguage(), rule.getKey(), context.getRulesProfile().getLanguage(),
106 context.getRulesProfile().getName());
107 List<ActiveRuleChange> changes = new ArrayList<>();
108 ActiveRuleChange change = null;
110 ActiveRuleWrapper activeRule = context.getActiveRule();
111 ActiveRuleKey activeRuleKey = ActiveRuleKey.of(context.getRulesProfile(), rule.getKey());
112 if (activeRule == null) {
113 if (activation.isReset()) {
114 // ignore reset when rule is not activated
117 change = handleNewRuleActivation(activation, context, rule, activeRuleKey);
121 // No change if propagating to descendants, but child profile already overrides rule
122 if (!context.isCascading() || !activeRule.get().doesOverride()) {
123 change = new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, activeRuleKey, rule);
124 handleUpdatedRuleActivation(activation, context, change, activeRule);
126 if (isSame(change, activeRule) || (context.isCascading() && activeRule.get().getInheritance() != null && !isSameAsParent(change,
128 // The rule config hasn't changed; or the rule is being propagated but the parent has a different config,
129 // which means the rule was overridden by a profile in the inheritance chain
135 if (change != null) {
137 persist(change, context, dbSession);
140 if (!changes.isEmpty()) {
141 updateProfileDates(dbSession, context);
144 // get all inherited profiles
145 for (QProfileDto child : context.getChildProfiles()) {
146 context.selectChild(child);
147 changes.addAll(doActivateRecursively(dbSession, activation, context));
153 private void handleUpdatedRuleActivation(RuleActivation activation, RuleActivationContext context, ActiveRuleChange change,
154 ActiveRuleWrapper activeRule) {
155 if (context.isCascading() && activeRule.get().getInheritance() == null) {
156 // The rule is being propagated, but it was activated directly on this profile before
157 change.setSeverity(activeRule.get().getSeverityString());
158 for (ActiveRuleParamDto activeParam : activeRule.getParams()) {
159 change.setParameter(activeParam.getKey(), activeParam.getValue());
161 change.setInheritance(isSameAsParent(change, context) ? ActiveRuleInheritance.INHERITED : ActiveRuleInheritance.OVERRIDES);
163 applySeverityAndPrioritizedRuleAndParamToChange(activation, context, change);
164 if (!context.isCascading() && context.getParentActiveRule() != null) {
165 // override rule which is already declared on parents
166 change.setInheritance(isSameAsParent(change, context) ? ActiveRuleInheritance.INHERITED : ActiveRuleInheritance.OVERRIDES);
171 private ActiveRuleChange handleNewRuleActivation(RuleActivation activation, RuleActivationContext context, RuleDto rule,
172 ActiveRuleKey activeRuleKey) {
173 ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, activeRuleKey, rule);
174 applySeverityAndPrioritizedRuleAndParamToChange(activation, context, change);
175 if (context.isCascading() || context.getParentActiveRule() != null) {
176 change.setInheritance(isSameAsParent(change, context) ? ActiveRuleInheritance.INHERITED : ActiveRuleInheritance.OVERRIDES);
181 private void updateProfileDates(DbSession dbSession, RuleActivationContext context) {
182 RulesProfileDto ruleProfile = context.getRulesProfile();
183 ruleProfile.setRulesUpdatedAtAsDate(new Date(context.getDate()));
184 db.qualityProfileDao().update(dbSession, ruleProfile);
186 if (userSession.isLoggedIn()) {
187 context.getProfiles().forEach(p -> db.qualityProfileDao().update(dbSession,
188 OrgQProfileDto.from(p).setUserUpdatedAt(context.getDate())));
193 * Update severity, prioritizedRule and params
195 private void applySeverityAndPrioritizedRuleAndParamToChange(RuleActivation request, RuleActivationContext context,
196 ActiveRuleChange change) {
197 RuleWrapper rule = context.getRule();
198 ActiveRuleWrapper activeRule = context.getActiveRule();
199 ActiveRuleWrapper parentActiveRule = context.getParentActiveRule();
201 if (request.isReset()) {
202 applySeverityAndPrioritizedRuleAndParamsWhenResetRequested(change, rule, parentActiveRule);
203 } else if (context.getRulesProfile().isBuiltIn()) {
204 applySeverityAndPrioritizedRuleAndParamsWhenBuiltInProfile(request, context, change, rule);
206 applySeverityAndPrioritizedRuleAndParamsWhenNonBuiltInProfile(request, context, change, rule, activeRule, parentActiveRule);
210 private void applySeverityAndPrioritizedRuleAndParamsWhenResetRequested(ActiveRuleChange change, RuleWrapper rule,
211 @Nullable ActiveRuleWrapper parentActiveRule) {
212 String severity = firstNonNull(
213 parentActiveRule != null ? parentActiveRule.get().getSeverityString() : null,
214 rule.get().getSeverityString());
215 change.setSeverity(severity);
216 change.setPrioritizedRule(parentActiveRule != null && parentActiveRule.get().isPrioritizedRule());
218 for (RuleParamDto ruleParamDto : rule.getParams()) {
219 String paramKey = ruleParamDto.getName();
220 // load params from parent profile, else from default values
221 String paramValue = firstNonNull(
222 parentActiveRule != null ? parentActiveRule.getParamValue(paramKey) : null,
223 rule.getParamDefaultValue(paramKey));
225 change.setParameter(paramKey, validateParam(ruleParamDto, paramValue));
229 private void applySeverityAndPrioritizedRuleAndParamsWhenBuiltInProfile(RuleActivation request, RuleActivationContext context,
230 ActiveRuleChange change, RuleWrapper rule) {
231 // for builtin quality profiles, the severity from profile, when null use the default severity of the rule
232 String severity = firstNonNull(request.getSeverity(), rule.get().getSeverityString());
233 change.setSeverity(severity);
235 boolean prioritizedRule = TRUE.equals(request.isPrioritizedRule());
236 change.setPrioritizedRule(prioritizedRule);
238 for (RuleParamDto ruleParamDto : rule.getParams()) {
239 String paramKey = ruleParamDto.getName();
240 // use the value defined in the profile definition, else the rule default value
241 String paramValue = firstNonNull(
242 context.getRequestedParamValue(request, paramKey),
243 rule.getParamDefaultValue(paramKey));
244 change.setParameter(paramKey, validateParam(ruleParamDto, paramValue));
249 * 1. apply requested severity and param
250 * 2. if rule activated and overridden - apply user value
251 * 3. apply parent value
254 private void applySeverityAndPrioritizedRuleAndParamsWhenNonBuiltInProfile(RuleActivation request, RuleActivationContext context,
255 ActiveRuleChange change,
256 RuleWrapper rule, @Nullable ActiveRuleWrapper activeRule, @Nullable ActiveRuleWrapper parentActiveRule) {
257 String severity = getSeverityForNonBuiltInProfile(request, rule, activeRule, parentActiveRule);
258 boolean prioritizedRule = getPrioritizedRuleForNonBuiltInProfile(request, activeRule, parentActiveRule);
259 change.setSeverity(severity);
260 change.setPrioritizedRule(prioritizedRule);
262 for (RuleParamDto ruleParamDto : rule.getParams()) {
263 String paramKey = ruleParamDto.getName();
264 String parentValue = parentActiveRule != null ? parentActiveRule.getParamValue(paramKey) : null;
266 if (context.hasRequestedParamValue(request, paramKey)) {
267 // If the request contains the parameter then we're using either value from request, or parent value, or default value
268 paramValue = firstNonNull(
269 context.getRequestedParamValue(request, paramKey),
271 rule.getParamDefaultValue(paramKey));
272 } else if (activeRule != null) {
273 // If the request doesn't contain the parameter, then we're using either user value from db, or parent value if rule inherited,
275 paramValue = firstNonNull(
276 activeRule.get().doesOverride() ? activeRule.getParamValue(paramKey) : null,
277 parentValue == null ? activeRule.getParamValue(paramKey) : parentValue,
278 rule.getParamDefaultValue(paramKey));
280 paramValue = firstNonNull(
282 rule.getParamDefaultValue(paramKey));
284 change.setParameter(paramKey, validateParam(ruleParamDto, paramValue));
288 private static String getSeverityForNonBuiltInProfile(RuleActivation request, RuleWrapper rule, @Nullable ActiveRuleWrapper activeRule,
289 @Nullable ActiveRuleWrapper parentActiveRule) {
291 if (activeRule != null) {
292 ActiveRuleDto activeRuleDto = activeRule.get();
293 // load severity from request, else keep existing one (if overridden), else from parent if rule inherited, else from default
294 severity = firstNonNull(
295 request.getSeverity(),
296 activeRuleDto.doesOverride() ? activeRuleDto.getSeverityString() : null,
297 parentActiveRule != null ? parentActiveRule.get().getSeverityString() : activeRuleDto.getSeverityString(),
298 rule.get().getSeverityString());
300 // load severity from request, else from parent, else from default
301 severity = firstNonNull(
302 request.getSeverity(),
303 parentActiveRule != null ? parentActiveRule.get().getSeverityString() : null,
304 rule.get().getSeverityString());
309 private static boolean getPrioritizedRuleForNonBuiltInProfile(RuleActivation request, @Nullable ActiveRuleWrapper activeRule,
310 @Nullable ActiveRuleWrapper parentActiveRule) {
311 boolean prioritizedRule;
312 if (activeRule != null) {
313 ActiveRuleDto activeRuleDto = activeRule.get();
314 // load prioritizedRule from request, else keep existing one (if overridden), else from parent if rule inherited, else 'false'
315 prioritizedRule = firstNonNull(
316 request.isPrioritizedRule(),
317 activeRuleDto.doesOverride() ? activeRuleDto.isPrioritizedRule() : null,
318 parentActiveRule != null && parentActiveRule.get().isPrioritizedRule());
320 // load prioritizedRule from request, else from parent, else 'false'
321 prioritizedRule = firstNonNull(
322 request.isPrioritizedRule(),
323 parentActiveRule != null && parentActiveRule.get().isPrioritizedRule());
325 return prioritizedRule;
328 private void persist(ActiveRuleChange change, RuleActivationContext context, DbSession dbSession) {
329 ActiveRuleDto activeRule = null;
330 if (change.getType() == ActiveRuleChange.Type.ACTIVATED) {
331 activeRule = doInsert(change, context, dbSession);
332 } else if (change.getType() == ActiveRuleChange.Type.DEACTIVATED) {
333 ActiveRuleDao dao = db.activeRuleDao();
334 activeRule = dao.delete(dbSession, change.getKey()).orElse(null);
336 } else if (change.getType() == ActiveRuleChange.Type.UPDATED) {
337 activeRule = doUpdate(change, context, dbSession);
339 change.setActiveRule(activeRule);
341 QProfileChangeDto dto = change.toDto(userSession.getUuid());
342 dto.setSqVersion(sonarQubeVersion.toString());
344 db.qProfileChangeDao().insert(dbSession, dto);
347 private ActiveRuleDto doInsert(ActiveRuleChange change, RuleActivationContext context, DbSession dbSession) {
348 ActiveRuleDao dao = db.activeRuleDao();
349 RuleWrapper rule = context.getRule();
351 ActiveRuleDto activeRule = new ActiveRuleDto();
352 activeRule.setProfileUuid(context.getRulesProfile().getUuid());
353 activeRule.setRuleUuid(rule.get().getUuid());
354 activeRule.setKey(ActiveRuleKey.of(context.getRulesProfile(), rule.get().getKey()));
355 String severity = change.getSeverity();
356 if (severity != null) {
357 activeRule.setSeverity(severity);
359 activeRule.setPrioritizedRule(TRUE.equals(change.isPrioritizedRule()));
360 ActiveRuleInheritance inheritance = change.getInheritance();
361 if (inheritance != null) {
362 activeRule.setInheritance(inheritance.name());
364 activeRule.setUpdatedAt(system2.now());
365 activeRule.setCreatedAt(system2.now());
366 dao.insert(dbSession, activeRule);
367 List<ActiveRuleParamDto> params = new ArrayList<>();
368 for (Map.Entry<String, String> param : change.getParameters().entrySet()) {
369 if (param.getValue() != null) {
370 ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(rule.getParam(param.getKey()));
371 paramDto.setValue(param.getValue());
372 params.add(paramDto);
373 dao.insertParam(dbSession, activeRule, paramDto);
376 context.register(activeRule, params);
380 private ActiveRuleDto doUpdate(ActiveRuleChange change, RuleActivationContext context, DbSession dbSession) {
381 ActiveRuleWrapper activeRule = context.getActiveRule();
382 if (activeRule == null) {
385 ActiveRuleDao dao = db.activeRuleDao();
386 String severity = change.getSeverity();
387 ActiveRuleDto ruleDto = activeRule.get();
388 if (severity != null) {
389 ruleDto.setSeverity(severity);
391 Boolean prioritizedRule = change.isPrioritizedRule();
392 if (prioritizedRule != null) {
393 ruleDto.setPrioritizedRule(prioritizedRule);
395 ActiveRuleInheritance inheritance = change.getInheritance();
396 if (inheritance != null) {
397 ruleDto.setInheritance(inheritance.name());
399 ruleDto.setUpdatedAt(system2.now());
400 dao.update(dbSession, ruleDto);
402 for (Map.Entry<String, String> param : change.getParameters().entrySet()) {
403 ActiveRuleParamDto activeRuleParamDto = activeRule.getParam(param.getKey());
404 if (activeRuleParamDto == null) {
406 if (param.getValue() != null) {
407 activeRuleParamDto = ActiveRuleParamDto.createFor(context.getRule().getParam(param.getKey()));
408 activeRuleParamDto.setValue(param.getValue());
409 dao.insertParam(dbSession, ruleDto, activeRuleParamDto);
412 if (param.getValue() != null) {
413 activeRuleParamDto.setValue(param.getValue());
414 dao.updateParam(dbSession, activeRuleParamDto);
416 dao.deleteParam(dbSession, activeRuleParamDto);
423 public List<ActiveRuleChange> deactivate(DbSession dbSession, RuleActivationContext context, String ruleUuid, boolean force) {
424 context.reset(ruleUuid);
425 return doDeactivateRecursively(dbSession, context, force);
428 private List<ActiveRuleChange> doDeactivateRecursively(DbSession dbSession, RuleActivationContext context, boolean force) {
429 List<ActiveRuleChange> changes = new ArrayList<>();
430 ActiveRuleWrapper activeRule = context.getActiveRule();
431 if (activeRule != null) {
432 checkRequest(force || context.isCascading() || activeRule.get().getInheritance() == null || isAllowDisableInheritedRules(),
433 "Cannot deactivate inherited rule '%s'", context.getRule().get().getKey());
435 ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.DEACTIVATED, activeRule.get(), context.getRule().get());
437 persist(change, context, dbSession);
440 // get all inherited profiles (they are not built-in by design)
441 context.getChildProfiles().forEach(child -> {
442 context.selectChild(child);
443 changes.addAll(doDeactivateRecursively(dbSession, context, force));
446 if (!changes.isEmpty()) {
447 updateProfileDates(dbSession, context);
453 private boolean isAllowDisableInheritedRules() {
454 return configuration.getBoolean(CorePropertyDefinitions.ALLOW_DISABLE_INHERITED_RULES).orElse(true);
458 private String validateParam(RuleParamDto ruleParam, @Nullable String value) {
460 RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType());
461 if (ruleParamType.multiple()) {
462 List<String> values = Splitter.on(",").splitToList(value);
463 typeValidations.validate(values, ruleParamType.type(), ruleParamType.values());
465 typeValidations.validate(value, ruleParamType.type(), ruleParamType.values());
471 public RuleActivationContext createContextForBuiltInProfile(DbSession dbSession, RulesProfileDto builtInProfile,
472 Collection<String> ruleUuids) {
473 checkArgument(builtInProfile.isBuiltIn(), "Rules profile with UUID %s is not built-in", builtInProfile.getUuid());
475 RuleActivationContext.Builder builder = new RuleActivationContext.Builder();
476 builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession));
479 completeWithRules(dbSession, builder, ruleUuids);
481 // load org profiles. Their parents are null by nature.
482 List<QProfileDto> profiles = db.qualityProfileDao().selectQProfilesByRuleProfile(dbSession, builtInProfile);
483 builder.setProfiles(profiles);
484 builder.setBaseProfile(builtInProfile);
487 Collection<String> ruleProfileUuids = Stream
488 .concat(Stream.of(builtInProfile.getUuid()), profiles.stream().map(QProfileDto::getRulesProfileUuid))
489 .collect(Collectors.toSet());
490 completeWithActiveRules(dbSession, builder, ruleUuids, ruleProfileUuids);
491 return builder.build();
494 public RuleActivationContext createContextForUserProfile(DbSession dbSession, QProfileDto profile, Collection<String> ruleUuids) {
495 checkArgument(!profile.isBuiltIn(), "Profile with UUID %s is built-in", profile.getKee());
496 RuleActivationContext.Builder builder = new RuleActivationContext.Builder();
497 builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession));
500 completeWithRules(dbSession, builder, ruleUuids);
503 List<QProfileDto> profiles = new ArrayList<>();
504 profiles.add(profile);
505 if (profile.getParentKee() != null) {
506 profiles.add(db.qualityProfileDao().selectByUuid(dbSession, profile.getParentKee()));
508 builder.setProfiles(profiles);
509 builder.setBaseProfile(RulesProfileDto.from(profile));
512 Collection<String> ruleProfileUuids = profiles.stream()
513 .map(QProfileDto::getRulesProfileUuid)
514 .collect(Collectors.toSet());
515 completeWithActiveRules(dbSession, builder, ruleUuids, ruleProfileUuids);
517 return builder.build();
520 DescendantProfilesSupplier createDescendantProfilesSupplier(DbSession dbSession) {
521 return (parents, ruleUuids) -> {
522 Collection<QProfileDto> profiles = db.qualityProfileDao().selectDescendants(dbSession, parents);
523 Set<String> ruleProfileUuids = profiles.stream()
524 .map(QProfileDto::getRulesProfileUuid)
525 .collect(Collectors.toSet());
526 Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleUuids, ruleProfileUuids);
527 List<String> activeRuleUuids = activeRules.stream().map(ActiveRuleDto::getUuid).toList();
528 List<ActiveRuleParamDto> activeRuleParams = db.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, activeRuleUuids);
529 return new DescendantProfilesSupplier.Result(profiles, activeRules, activeRuleParams);
533 private void completeWithRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<String> ruleUuids) {
534 List<RuleDto> rules = db.ruleDao().selectByUuids(dbSession, ruleUuids);
535 builder.setRules(rules);
536 builder.setRuleParams(db.ruleDao().selectRuleParamsByRuleUuids(dbSession, ruleUuids));
539 private void completeWithActiveRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<String> ruleUuids,
540 Collection<String> ruleProfileUuids) {
541 Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleUuids, ruleProfileUuids);
542 builder.setActiveRules(activeRules);
543 List<String> activeRuleUuids = activeRules.stream().map(ActiveRuleDto::getUuid).toList();
544 builder.setActiveRuleParams(db.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, activeRuleUuids));
547 private static boolean isSame(ActiveRuleChange change, ActiveRuleWrapper activeRule) {
548 ActiveRuleInheritance inheritance = change.getInheritance();
549 if (inheritance != null && !inheritance.name().equals(activeRule.get().getInheritance())) {
552 String severity = change.getSeverity();
553 if (severity != null && !severity.equals(activeRule.get().getSeverityString())) {
556 Boolean prioritizedRule = change.isPrioritizedRule();
557 if (prioritizedRule != null && prioritizedRule != activeRule.get().isPrioritizedRule()) {
560 for (Map.Entry<String, String> changeParam : change.getParameters().entrySet()) {
561 String activeParamValue = activeRule.getParamValue(changeParam.getKey());
562 if (changeParam.getValue() == null && activeParamValue != null) {
565 if (changeParam.getValue() != null && (activeParamValue == null || !StringUtils.equals(changeParam.getValue(), activeParamValue))) {
572 private static boolean isSameAsParent(ActiveRuleChange change, RuleActivationContext context) {
573 ActiveRuleWrapper parentActiveRule = context.getParentActiveRule();
574 if (parentActiveRule == null) {
577 if (!StringUtils.equals(change.getSeverity(), parentActiveRule.get().getSeverityString())) {
580 if (change.isPrioritizedRule() != null && !Objects.equals(change.isPrioritizedRule(), parentActiveRule.get().isPrioritizedRule())) {
583 for (Map.Entry<String, String> entry : change.getParameters().entrySet()) {
584 if (entry.getValue() != null && !entry.getValue().equals(parentActiveRule.getParamValue(entry.getKey()))) {
592 private static String firstNonNull(String... strings) {
593 for (String s : strings) {
601 private static boolean firstNonNull(Boolean... booleans) {
602 for (Boolean b : booleans) {