import org.sonar.server.platform.web.RegisterServletFilters;
import org.sonar.server.qualitygate.RegisterQualityGates;
import org.sonar.server.qualityprofile.CachingRuleActivator;
+import org.sonar.server.qualityprofile.CachingRuleActivatorContextFactory;
import org.sonar.server.qualityprofile.RegisterQualityProfiles;
import org.sonar.server.rule.RegisterRules;
import org.sonar.server.startup.ClearRulesOverloadedDebt;
IndexerStartupTask.class,
RegisterMetrics.class,
RegisterQualityGates.class,
- CachingRuleActivator.class,
RegisterRules.class,
+ CachingRuleActivatorContextFactory.class,
+ CachingRuleActivator.class,
RegisterQualityProfiles.class,
RegisterPermissionTemplates.class,
RenameDeprecatedPropertyKeys.class,
.maximumSize(10_000)
.build();
- public CachingRuleActivator(System2 system2, DbClient db, RuleIndex ruleIndex, RuleActivatorContextFactory contextFactory, TypeValidations typeValidations,
+ public CachingRuleActivator(System2 system2, DbClient db, RuleIndex ruleIndex, CachingRuleActivatorContextFactory contextFactory, TypeValidations typeValidations,
ActiveRuleIndexer activeRuleIndexer, UserSession userSession) {
super(system2, db, ruleIndex, contextFactory, typeValidations, activeRuleIndexer, userSession);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualityprofile;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import org.picocontainer.Startable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.util.stream.Collectors;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.qualityprofile.ActiveRuleDto;
+import org.sonar.db.qualityprofile.ActiveRuleKey;
+import org.sonar.db.qualityprofile.ActiveRuleParamDto;
+import org.sonar.db.rule.RuleDto;
+
+public class CachingRuleActivatorContextFactory extends RuleActivatorContextFactory implements Startable {
+ private final DbClient dbClient;
+ private final Map<RuleKey, RuleDto> rulesByRuleKey = new HashMap<>();
+ private final Cache<String, Map<RuleKey, ActiveRuleDto>> childrenByParentKey = CacheBuilder.newBuilder()
+ .maximumSize(10)
+ .build();
+
+ public CachingRuleActivatorContextFactory(DbClient db) {
+ super(db);
+ this.dbClient = db;
+ }
+
+ @Override
+ public void start() {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ dbClient.ruleDao().selectAll(dbSession).forEach(rule -> rulesByRuleKey.put(rule.getKey(), rule));
+ }
+ }
+
+ @Override
+ public void stop() {
+ // nothing to do
+ }
+
+ @Override
+ Optional<RuleDto> getRule(DbSession dbSession, RuleKey ruleKey) {
+ return Optional.ofNullable(rulesByRuleKey.get(ruleKey));
+ }
+
+ @Override
+ Optional<ActiveRuleDto> getActiveRule(DbSession session, ActiveRuleKey key) {
+ try {
+ String profileKey = key.qProfile();
+ Map<RuleKey, ActiveRuleDto> profileActiveRulesByRuleKey = childrenByParentKey.get(
+ profileKey,
+ () -> loadActiveRulesOfQualityProfile(session, profileKey));
+ return Optional.ofNullable(profileActiveRulesByRuleKey.get(key.ruleKey()));
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(e.getCause());
+ }
+ }
+
+ private Map<RuleKey, ActiveRuleDto> loadActiveRulesOfQualityProfile(DbSession session, String profileKey) {
+ return dbClient.activeRuleDao().selectByProfileKey(session, profileKey).stream()
+ .collect(Collectors.uniqueIndex(dto -> dto.getKey().ruleKey()));
+ }
+
+ @Override
+ List<ActiveRuleParamDto> getActiveRuleParams(DbSession session, ActiveRuleDto activeRuleDto) {
+ return super.getActiveRuleParams(session, activeRuleDto);
+ }
+}
*/
package org.sonar.server.qualityprofile;
-import com.google.common.base.Optional;
import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.ServerSide;
import org.sonar.db.DbClient;
}
private RuleDto initRule(RuleKey ruleKey, RuleActivatorContext context, DbSession dbSession) {
- Optional<RuleDto> rule = db.ruleDao().selectByKey(dbSession, ruleKey);
+ Optional<RuleDto> rule = getRule(dbSession, ruleKey);
checkRequest(rule.isPresent(), "Rule not found: %s", ruleKey);
context.setRule(rule.get());
context.setRuleParams(db.ruleDao().selectRuleParamsByRuleKey(dbSession, rule.get().getKey()));
private void initActiveRules(String profileKey, RuleKey ruleKey, RuleActivatorContext context, DbSession session, boolean parent) {
ActiveRuleKey key = ActiveRuleKey.of(profileKey, ruleKey);
- Optional<ActiveRuleDto> activeRule = db.activeRuleDao().selectByKey(session, key);
+ Optional<ActiveRuleDto> activeRule = getActiveRule(session, key);
Collection<ActiveRuleParamDto> activeRuleParams = null;
if (activeRule.isPresent()) {
- activeRuleParams = db.activeRuleDao().selectParamsByActiveRuleId(session, activeRule.get().getId());
+ activeRuleParams = getActiveRuleParams(session, activeRule.get());
}
if (parent) {
- context.setParentActiveRule(activeRule.orNull());
+ context.setParentActiveRule(activeRule.orElse(null));
context.setParentActiveRuleParams(activeRuleParams);
} else {
- context.setActiveRule(activeRule.orNull());
+ context.setActiveRule(activeRule.orElse(null));
context.setActiveRuleParams(activeRuleParams);
}
}
+
+ Optional<RuleDto> getRule(DbSession dbSession, RuleKey ruleKey) {
+ return Optional.ofNullable(db.ruleDao().selectByKey(dbSession, ruleKey).orNull());
+ }
+
+ Optional<ActiveRuleDto> getActiveRule(DbSession session, ActiveRuleKey key) {
+ return Optional.ofNullable(db.activeRuleDao().selectByKey(session, key).orNull());
+ }
+
+ List<ActiveRuleParamDto> getActiveRuleParams(DbSession session, ActiveRuleDto activeRuleDto) {
+ return db.activeRuleDao().selectParamsByActiveRuleId(session, activeRuleDto.getId());
+ }
}
import org.sonar.db.loadedtemplate.LoadedTemplateDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
+import org.sonar.server.language.LanguageTesting;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.tester.UserSessionRule;
import static org.sonar.core.util.UtcDateUtils.formatDateTime;
public class RegisterQualityProfilesTest {
- private static final DummyLanguage FOO_LANGUAGE = new DummyLanguage("foo");
- private static final DummyLanguage BAR_LANGUAGE = new DummyLanguage("bar");
+ private static final Language FOO_LANGUAGE = LanguageTesting.newLanguage("foo", "foo", "foo");
+ private static final Language BAR_LANGUAGE = LanguageTesting.newLanguage("bar", "bar", "bar");
private static final String TABLE_RULES_PROFILES = "RULES_PROFILES";
private static final String TYPE_QUALITY_PROFILE = "QUALITY_PROFILE";
private static final String SONAR_WAY_QP_NAME = "Sonar way";
return new RegisterQualityProfiles(
dbClient,
new QProfileFactory(dbClient, mockedUuidFactory, mockedSystem2),
- new CachingRuleActivator(mockedSystem2, dbClient, null, new RuleActivatorContextFactory(dbClient), null, null, userSessionRule),
+ new CachingRuleActivator(mockedSystem2, dbClient, null, new CachingRuleActivatorContextFactory(dbClient), null, null, userSessionRule),
definitions,
languages,
mockedActiveRuleIndexer);
}
}
- private static class DummyLanguage implements Language {
- private final String key;
-
- private DummyLanguage(String key) {
- this.key = key;
- }
-
- @Override
- public String getKey() {
- return key;
- }
-
- @Override
- public String getName() {
- return key;
- }
-
- @Override
- public String[] getFileSuffixes() {
- return new String[] {key};
- }
- }
-
private String computeLoadedTemplateType(DummyProfileDefinition qpDefinition) {
String qpIdentifier = lowerCase(qpDefinition.getLanguage()) + ":" + qpDefinition.getName();
return format("%s.%s", TYPE_QUALITY_PROFILE, DigestUtils.md5Hex(qpIdentifier.getBytes(UTF_8)));