diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2022-02-01 15:16:25 -0600 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-02-22 20:02:46 +0000 |
commit | 60c1a4038e041a342dda9810e6fd761d66b01bdb (patch) | |
tree | 0e76b4252e4d7d257cf4ddcb6f081996bb1e03ab /server/sonar-db-dao | |
parent | 9694d4113bf401b84e86e0223dbea8f5339388d8 (diff) | |
download | sonarqube-60c1a4038e041a342dda9810e6fd761d66b01bdb.tar.gz sonarqube-60c1a4038e041a342dda9810e6fd761d66b01bdb.zip |
SONAR-15994 Migrate Sonarqube IOC framework from Pico to Spring
Diffstat (limited to 'server/sonar-db-dao')
8 files changed, 145 insertions, 55 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java index bf75d7a5965..d128c08158f 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java @@ -157,16 +157,19 @@ import org.sonar.db.user.UserTokenDto; import org.sonar.db.user.UserTokenMapper; import org.sonar.db.webhook.WebhookDeliveryMapper; import org.sonar.db.webhook.WebhookMapper; +import org.springframework.beans.factory.annotation.Autowired; public class MyBatis implements Startable { private final List<MyBatisConfExtension> confExtensions; private final Database database; private SqlSessionFactory sessionFactory; + @Autowired(required = false) public MyBatis(Database database) { this(database, null); } + @Autowired(required = false) public MyBatis(Database database, @Nullable MyBatisConfExtension[] confExtensions) { this.confExtensions = confExtensions == null ? Collections.emptyList() : Arrays.asList(confExtensions); this.database = database; diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java index eb1d6a09169..2567bfbc8f0 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java @@ -19,6 +19,7 @@ */ package org.sonar.db.audit; +import javax.annotation.Priority; import org.sonar.db.DbSession; import org.sonar.db.audit.model.ComponentKeyNewValue; import org.sonar.db.audit.model.ComponentNewValue; @@ -38,6 +39,7 @@ import org.sonar.db.audit.model.UserPermissionNewValue; import org.sonar.db.audit.model.UserTokenNewValue; import org.sonar.db.audit.model.WebhookNewValue; +@Priority(2) public class NoOpAuditPersister implements AuditPersister { @Override public void addUserGroup(DbSession dbSession, UserGroupNewValue newValue) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalPropertiesDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalPropertiesDao.java index 235b832177a..132e5b08c93 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalPropertiesDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalPropertiesDao.java @@ -57,11 +57,7 @@ public class InternalPropertiesDao implements Dao { private static final Optional<String> OPTIONAL_OF_EMPTY_STRING = Optional.of(""); private final System2 system2; - private AuditPersister auditPersister; - - public InternalPropertiesDao(System2 system2) { - this.system2 = system2; - } + private final AuditPersister auditPersister; public InternalPropertiesDao(System2 system2, AuditPersister auditPersister) { this.system2 = system2; @@ -89,7 +85,7 @@ public class InternalPropertiesDao implements Dao { mapper.insertAsText(key, value, now); } - if (auditPersister != null && auditPersister.isTrackedProperty(key)) { + if (auditPersister.isTrackedProperty(key)) { if (deletedRows > 0) { auditPersister.updateProperty(dbSession, new PropertyNewValue(key, value), false); } else { @@ -112,7 +108,7 @@ public class InternalPropertiesDao implements Dao { int deletedRows = mapper.deleteByKey(key); mapper.insertAsEmpty(key, system2.now()); - if (auditPersister != null && auditPersister.isTrackedProperty(key)) { + if (auditPersister.isTrackedProperty(key)) { if (deletedRows > 0) { auditPersister.updateProperty(dbSession, new PropertyNewValue(key, ""), false); } else { @@ -124,7 +120,7 @@ public class InternalPropertiesDao implements Dao { public void delete(DbSession dbSession, String key) { int deletedRows = getMapper(dbSession).deleteByKey(key); - if (auditPersister != null && deletedRows > 0 && auditPersister.isTrackedProperty(key)) { + if (deletedRows > 0 && auditPersister.isTrackedProperty(key)) { auditPersister.deleteProperty(dbSession, new PropertyNewValue(key), false); } } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java index b312959a5ce..96f261556af 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java @@ -20,15 +20,15 @@ package org.sonar.db; import org.junit.Test; -import org.sonar.core.platform.ComponentContainer; +import org.sonar.core.platform.ListContainer; import static org.assertj.core.api.Assertions.assertThat; public class DaoModuleTest { @Test public void verify_count_of_added_components() { - ComponentContainer container = new ComponentContainer(); + ListContainer container = new ListContainer(); new DaoModule().configure(container); - assertThat(container.size()).isGreaterThan(1); + assertThat(container.getAddedObjects()).hasSizeGreaterThan(1); } } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/MyBatisTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/MyBatisTest.java index 63b11946b31..4414ef3309a 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/MyBatisTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/MyBatisTest.java @@ -21,7 +21,6 @@ package org.sonar.db; import org.apache.ibatis.session.Configuration; import org.hamcrest.core.Is; -import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -46,11 +45,6 @@ public class MyBatisTest { private MyBatis underTest = new MyBatis(database); - @After - public void tearDown() { - underTest.stop(); - } - @Test public void shouldConfigureMyBatis() { underTest.start(); diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java index 9e3e83f17e8..d8d9e8bb483 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java @@ -28,7 +28,6 @@ import java.util.Map; import java.util.stream.Stream; import javax.annotation.Nullable; import org.apache.commons.dbcp2.BasicDataSource; -import org.picocontainer.containers.TransientPicoContainer; import org.sonar.api.utils.System2; import org.sonar.core.util.SequenceUuidFactory; import org.sonar.core.util.UuidFactory; @@ -145,15 +144,16 @@ public class DbTester extends AbstractDbTester<TestDbImpl> { } private void initDbClient() { - TransientPicoContainer ioc = new TransientPicoContainer(); - ioc.addComponent(auditPersister); - ioc.addComponent(db.getMyBatis()); - ioc.addComponent(system2); - ioc.addComponent(uuidFactory); - for (Class daoClass : DaoModule.classes()) { - ioc.addComponent(daoClass); + FastSpringContainer ioc = new FastSpringContainer(); + ioc.add(auditPersister); + ioc.add(db.getMyBatis()); + ioc.add(system2); + ioc.add(uuidFactory); + for (Class<?> daoClass : DaoModule.classes()) { + ioc.add(daoClass); } - List<Dao> daos = ioc.getComponents(Dao.class); + ioc.start(); + List<Dao> daos = ioc.getComponentsByType(Dao.class); client = new DbClient(db.getDatabase(), db.getMyBatis(), new TestDBSessions(db.getMyBatis()), daos.toArray(new Dao[daos.size()])); } diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/FastSpringContainer.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/FastSpringContainer.java new file mode 100644 index 00000000000..47b5cded6b8 --- /dev/null +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/FastSpringContainer.java @@ -0,0 +1,104 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.db; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; +import org.sonar.core.platform.Container; +import org.sonar.core.platform.StartableBeanPostProcessor; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; +import org.springframework.context.support.GenericApplicationContext; + +/** + * A fast(er) Spring container. It doesn't support several things that are supported in + * {@link org.sonar.core.platform.SpringComponentContainer}, such as: + * <ul> + * <li>Adding extensions</li> + * <li>Use of annotations</li> + * <li>Adding duplicate components from different Classloaders</li> + * <li>Hierarchy of container</li> + * <li>Different initialization strategies</li> + * </ul> + */ +public class FastSpringContainer implements Container { + private final GenericApplicationContext context = new GenericApplicationContext(); + + public FastSpringContainer() { + ((AbstractAutowireCapableBeanFactory) context.getBeanFactory()).setParameterNameDiscoverer(null); + add(StartableBeanPostProcessor.class); + } + + @Override + public Container add(Object... objects) { + for (Object o : objects) { + if (o instanceof Class) { + Class<?> clazz = (Class<?>) o; + context.registerBean(clazz.getName(), clazz); + } else { + registerInstance(o); + } + } + return this; + } + + public void start() { + context.refresh(); + } + + private <T> void registerInstance(T instance) { + Supplier<T> supplier = () -> instance; + Class<T> clazz = (Class<T>) instance.getClass(); + context.registerBean(clazz.getName(), clazz, supplier); + } + + @Override + public <T> T getComponentByType(Class<T> type) { + try { + return context.getBean(type); + } catch (Exception t) { + throw new IllegalStateException("Unable to load component " + type, t); + } + } + + @Override public <T> Optional<T> getOptionalComponentByType(Class<T> type) { + try { + return Optional.of(context.getBean(type)); + } catch (NoSuchBeanDefinitionException t) { + return Optional.empty(); + } + } + + @Override + public <T> List<T> getComponentsByType(Class<T> type) { + try { + return new ArrayList<>(context.getBeansOfType(type).values()); + } catch (Exception t) { + throw new IllegalStateException("Unable to load components " + type, t); + } + } + + @Override + public Container getParent() { + return null; + } +} diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/SQDatabase.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/SQDatabase.java index 169bf9763c2..dc515bfcd4f 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/SQDatabase.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/SQDatabase.java @@ -35,7 +35,8 @@ import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.utils.System2; import org.sonar.api.utils.Version; import org.sonar.api.utils.log.Loggers; -import org.sonar.core.platform.ComponentContainer; +import org.sonar.core.platform.Container; +import org.sonar.core.platform.SpringComponentContainer; import org.sonar.core.util.UuidFactoryFast; import org.sonar.core.util.logs.Profiler; import org.sonar.db.dialect.Dialect; @@ -43,15 +44,12 @@ import org.sonar.process.logging.LogbackHelper; import org.sonar.server.platform.db.migration.MigrationConfigurationModule; import org.sonar.server.platform.db.migration.engine.MigrationContainer; import org.sonar.server.platform.db.migration.engine.MigrationContainerImpl; -import org.sonar.server.platform.db.migration.engine.MigrationContainerPopulator; -import org.sonar.server.platform.db.migration.engine.MigrationContainerPopulatorImpl; import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl; import org.sonar.server.platform.db.migration.step.MigrationStep; import org.sonar.server.platform.db.migration.step.MigrationStepExecutionException; import org.sonar.server.platform.db.migration.step.MigrationSteps; import org.sonar.server.platform.db.migration.step.MigrationStepsExecutor; import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep; -import org.sonar.server.platform.db.migration.version.DbVersion; import static com.google.common.base.Preconditions.checkState; @@ -101,29 +99,23 @@ public class SQDatabase extends DefaultDatabase { } } - public static final class H2MigrationContainerPopulator extends MigrationContainerPopulatorImpl { - public H2MigrationContainerPopulator(DbVersion... dbVersions) { - super(H2StepExecutor.class, dbVersions); - } - } - public static final class H2StepExecutor implements MigrationStepsExecutor { private static final String STEP_START_PATTERN = "{}..."; private static final String STEP_STOP_PATTERN = "{}: {}"; - private final ComponentContainer componentContainer; + private final Container container; - public H2StepExecutor(ComponentContainer componentContainer) { - this.componentContainer = componentContainer; + public H2StepExecutor(Container container) { + this.container = container; } @Override public void execute(List<RegisteredMigrationStep> steps) { - steps.forEach(step -> execute(step, componentContainer)); + steps.forEach(step -> execute(step, container)); } - private void execute(RegisteredMigrationStep step, ComponentContainer componentContainer) { - MigrationStep migrationStep = componentContainer.getComponentByType(step.getStepClass()); + private void execute(RegisteredMigrationStep step, Container container) { + MigrationStep migrationStep = container.getComponentByType(step.getStepClass()); checkState(migrationStep != null, "Can not find instance of " + step.getStepClass()); execute(step, migrationStep); @@ -149,24 +141,23 @@ public class SQDatabase extends DefaultDatabase { } private void executeDbMigrations(NoopDatabase noopDatabase) { - ComponentContainer parentContainer = new ComponentContainer(); - parentContainer.add(noopDatabase); - parentContainer.add(H2MigrationContainerPopulator.class); + SpringComponentContainer container = new SpringComponentContainer(); + container.add(noopDatabase); MigrationConfigurationModule migrationConfigurationModule = new MigrationConfigurationModule(); - migrationConfigurationModule.configure(parentContainer); + migrationConfigurationModule.configure(container); // dependencies required by DB migrations - parentContainer.add(SonarRuntimeImpl.forSonarQube(Version.create(8, 0), SonarQubeSide.SERVER, SonarEdition.COMMUNITY)); - parentContainer.add(UuidFactoryFast.getInstance()); - parentContainer.add(System2.INSTANCE); - parentContainer.add(MapSettings.class); + container.add(SonarRuntimeImpl.forSonarQube(Version.create(8, 0), SonarQubeSide.SERVER, SonarEdition.COMMUNITY)); + container.add(UuidFactoryFast.getInstance()); + container.add(System2.INSTANCE); + container.add(MapSettings.class); - parentContainer.startComponents(); - - MigrationContainer migrationContainer = new MigrationContainerImpl(parentContainer, parentContainer.getComponentByType(MigrationContainerPopulator.class)); + container.startComponents(); + MigrationContainer migrationContainer = new MigrationContainerImpl(container, H2StepExecutor.class); MigrationSteps migrationSteps = migrationContainer.getComponentByType(MigrationSteps.class); - migrationContainer.getComponentByType(MigrationStepsExecutor.class) - .execute(migrationSteps.readAll()); + MigrationStepsExecutor executor = migrationContainer.getComponentByType(MigrationStepsExecutor.class); + + executor.execute(migrationSteps.readAll()); } private void createMigrationHistoryTable(NoopDatabase noopDatabase) { |