From 1c607e1946b43310099e57b755ebfe352679cf92 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Thu, 1 Sep 2016 17:20:29 +0200 Subject: [PATCH] SONAR-7675 add InternalPropertiesImpl to Web and Ce containers --- .../container/ComputeEngineContainerImpl.java | 2 + .../ComputeEngineContainerImplTest.java | 2 +- .../platformlevel/PlatformLevel4.java | 2 + .../server/property/InternalProperties.java | 49 ++++++++ .../property/InternalPropertiesImpl.java | 65 ++++++++++ .../sonar/server/property/package-info.java | 23 ++++ .../property/InternalPropertiesImplTest.java | 117 ++++++++++++++++++ 7 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/property/InternalProperties.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/property/InternalPropertiesImpl.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/property/package-info.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/property/InternalPropertiesImplTest.java diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index 27f5bec1cbb..fff798be3cf 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -115,6 +115,7 @@ import org.sonar.server.plugins.InstalledPluginReferentialFactory; import org.sonar.server.plugins.ServerExtensionInstaller; import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper; import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper; +import org.sonar.server.property.InternalPropertiesImpl; import org.sonar.server.qualityprofile.BuiltInProfiles; import org.sonar.server.qualityprofile.QProfileComparison; import org.sonar.server.qualityprofile.QProfileLookup; @@ -385,6 +386,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { ProjectAnalysisTaskModule.class, CeTaskProcessorModule.class, + InternalPropertiesImpl.class, ProjectSettingsFactory.class, }; } diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index b513dfa7ef6..98e1ba5c1e9 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -88,7 +88,7 @@ public class ComputeEngineContainerImplTest { assertThat(picoContainer.getComponentAdapters()) .hasSize( CONTAINER_ITSELF - + 79 // level 4 + + 80 // level 4 + 4 // content of CeConfigurationModule + 3 // content of CeHttpModule + 5 // content of CeQueueModule diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 1e7b008bc60..4ae90268689 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -177,6 +177,7 @@ import org.sonar.server.plugins.ws.UninstallAction; import org.sonar.server.plugins.ws.UpdatesAction; import org.sonar.server.project.ws.ProjectsWsModule; import org.sonar.server.projectlink.ws.ProjectLinksModule; +import org.sonar.server.property.InternalPropertiesImpl; import org.sonar.server.qualitygate.QualityGateModule; import org.sonar.server.qualityprofile.BuiltInProfiles; import org.sonar.server.qualityprofile.QProfileBackuper; @@ -635,6 +636,7 @@ public class PlatformLevel4 extends PlatformLevel { CeModule.class, CeWsModule.class, + InternalPropertiesImpl.class, ProjectSettingsFactory.class, // UI diff --git a/server/sonar-server/src/main/java/org/sonar/server/property/InternalProperties.java b/server/sonar-server/src/main/java/org/sonar/server/property/InternalProperties.java new file mode 100644 index 00000000000..f1d5a1be7b4 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/property/InternalProperties.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.property; + +import java.util.Optional; +import javax.annotation.Nullable; + +/** + * Allows to read and write internal properties. + */ +public interface InternalProperties { + + /** + * Read the value of the specified property. + * + * @return {@link Optional#empty()} if the property does not exist, an empty string if the property is empty, + * otherwise the value of the property as a String. + * + * @throws IllegalArgumentException if {@code propertyKey} is {@code null} or empty + */ + Optional read(String propertyKey); + + /** + * Write the value of the specified property. + *

+ * {@code null} and empty string are valid values which will persist the specified property as empty. + *

+ * + * @throws IllegalArgumentException if {@code propertyKey} is {@code null} or empty + */ + void write(String propertyKey, @Nullable String value); +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/property/InternalPropertiesImpl.java b/server/sonar-server/src/main/java/org/sonar/server/property/InternalPropertiesImpl.java new file mode 100644 index 00000000000..f99002d9dee --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/property/InternalPropertiesImpl.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.property; + +import java.util.Optional; +import javax.annotation.Nullable; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * A cache-less implementation of {@link InternalProperties} reading and writing to DB table INTERNAL_PROPERTIES. + */ +public class InternalPropertiesImpl implements InternalProperties { + private final DbClient dbClient; + + public InternalPropertiesImpl(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public Optional read(String propertyKey) { + checkPropertyKey(propertyKey); + + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.internalPropertiesDao().selectByKey(dbSession, propertyKey); + } + } + + @Override + public void write(String propertyKey, @Nullable String value) { + checkPropertyKey(propertyKey); + + try (DbSession dbSession = dbClient.openSession(false)) { + if (value == null || value.isEmpty()) { + dbClient.internalPropertiesDao().saveAsEmpty(dbSession, propertyKey); + } else { + dbClient.internalPropertiesDao().save(dbSession, propertyKey, value); + } + } + } + + private static void checkPropertyKey(@Nullable String propertyKey) { + checkArgument(propertyKey != null && !propertyKey.isEmpty(), "property key can't be null nor empty"); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/property/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/property/package-info.java new file mode 100644 index 00000000000..730caadf540 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/property/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.property; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/test/java/org/sonar/server/property/InternalPropertiesImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/property/InternalPropertiesImplTest.java new file mode 100644 index 00000000000..20c371ba256 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/property/InternalPropertiesImplTest.java @@ -0,0 +1,117 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.property; + +import java.util.Optional; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.property.InternalPropertiesDao; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class InternalPropertiesImplTest { + private static final String EMPTY_STRING = ""; + public static final String SOME_VALUE = "a value"; + public static final String SOME_KEY = "some key"; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private DbClient dbClient = mock(DbClient.class); + private DbSession dbSession = mock(DbSession.class); + private InternalPropertiesDao internalPropertiesDao = mock(InternalPropertiesDao.class); + private InternalPropertiesImpl underTest = new InternalPropertiesImpl(dbClient); + + @Before + public void setUp() throws Exception { + when(dbClient.openSession(false)).thenReturn(dbSession); + when(dbClient.internalPropertiesDao()).thenReturn(internalPropertiesDao); + } + + @Test + public void reads_throws_IAE_if_key_is_null() { + expectKeyNullOrEmptyIAE(); + + underTest.read(null); + } + + @Test + public void reads_throws_IAE_if_key_is_empty() { + expectKeyNullOrEmptyIAE(); + + underTest.read(EMPTY_STRING); + } + + @Test + public void reads_returns_optional_from_DAO() { + Optional value = Optional.of("bablabla"); + + when(internalPropertiesDao.selectByKey(dbSession, SOME_KEY)).thenReturn(value); + + assertThat(underTest.read(SOME_KEY)).isSameAs(value); + } + + @Test + public void write_throws_IAE_if_key_is_null() { + expectKeyNullOrEmptyIAE(); + + underTest.write(null, SOME_VALUE); + } + + @Test + public void writes_throws_IAE_if_key_is_empty() { + expectKeyNullOrEmptyIAE(); + + underTest.write(EMPTY_STRING, SOME_VALUE); + } + + @Test + public void write_calls_dao_saveAsEmpty_when_value_is_null() { + underTest.write(SOME_KEY, null); + + verify(internalPropertiesDao).saveAsEmpty(dbSession, SOME_KEY); + } + + @Test + public void write_calls_dao_saveAsEmpty_when_value_is_empty() { + underTest.write(SOME_KEY, EMPTY_STRING); + + verify(internalPropertiesDao).saveAsEmpty(dbSession, SOME_KEY); + } + + @Test + public void write_calls_dao_save_when_value_is_neither_null_nor_empty() { + underTest.write(SOME_KEY, SOME_VALUE); + + verify(internalPropertiesDao).save(dbSession, SOME_KEY, SOME_VALUE); + } + + private void expectKeyNullOrEmptyIAE() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("key can't be null nor empty"); + } +} -- 2.39.5