Browse Source

SONAR-11720 Set different memory defaults for EE+

tags/7.8
Michal Duda 5 years ago
parent
commit
dfcb1c01a4

+ 10
- 1
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.ce.container;

import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.IOException;
import java.util.Date;
@@ -38,6 +39,7 @@ import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.ce.CeDistributedInformationImpl;
import org.sonar.ce.StandaloneCeDistributedInformation;
import org.sonar.core.extension.ServiceLoaderWrapper;
import org.sonar.db.DbTester;
import org.sonar.db.property.PropertyDto;
import org.sonar.process.ProcessId;
@@ -48,6 +50,7 @@ import org.sonar.server.property.InternalProperties;
import static java.lang.String.valueOf;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX;
import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH;
import static org.sonar.process.ProcessProperties.Property.JDBC_PASSWORD;
@@ -68,9 +71,12 @@ public class ComputeEngineContainerImplTest {
public DbTester db = DbTester.create(System2.INSTANCE);

private ComputeEngineContainerImpl underTest;
private ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
private ProcessProperties processProperties = new ProcessProperties(serviceLoaderWrapper);

@Before
public void setUp() {
when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of());
underTest = new ComputeEngineContainerImpl();
underTest.setComputeEngineStatus(mock(ComputeEngineStatus.class));
}
@@ -148,7 +154,10 @@ public class ComputeEngineContainerImplTest {
}

private Properties getProperties() throws IOException {
Properties properties = ProcessProperties.defaults();
Properties properties = new Properties();
Props props = new Props(properties);
processProperties.completeDefaults(props);
properties = props.rawProperties();
File homeDir = tempFolder.newFolder();
File dataDir = new File(homeDir, "data");
dataDir.mkdirs();

+ 8
- 6
server/sonar-main/src/main/java/org/sonar/application/config/AppSettingsLoaderImpl.java View File

@@ -29,12 +29,13 @@ import java.util.Arrays;
import java.util.Properties;
import java.util.function.Consumer;
import org.slf4j.LoggerFactory;
import org.sonar.core.extension.ServiceLoaderWrapper;
import org.sonar.process.ConfigurationUtils;
import org.sonar.process.NetworkUtilsImpl;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.sonar.process.ProcessProperties.completeDefaults;
import static org.sonar.process.ProcessProperties.Property.PATH_HOME;

public class AppSettingsLoaderImpl implements AppSettingsLoader {
@@ -42,15 +43,16 @@ public class AppSettingsLoaderImpl implements AppSettingsLoader {
private final File homeDir;
private final String[] cliArguments;
private final Consumer<Props>[] consumers;
private final ServiceLoaderWrapper serviceLoaderWrapper;

public AppSettingsLoaderImpl(String[] cliArguments) {
this(cliArguments, detectHomeDir(),
new FileSystemSettings(), new JdbcSettings(), new ClusterSettings(NetworkUtilsImpl.INSTANCE));
public AppSettingsLoaderImpl(String[] cliArguments, ServiceLoaderWrapper serviceLoaderWrapper) {
this(cliArguments, detectHomeDir(), serviceLoaderWrapper, new FileSystemSettings(), new JdbcSettings(), new ClusterSettings(NetworkUtilsImpl.INSTANCE));
}

AppSettingsLoaderImpl(String[] cliArguments, File homeDir, Consumer<Props>... consumers) {
AppSettingsLoaderImpl(String[] cliArguments, File homeDir, ServiceLoaderWrapper serviceLoaderWrapper, Consumer<Props>... consumers) {
this.cliArguments = cliArguments;
this.homeDir = homeDir;
this.serviceLoaderWrapper = serviceLoaderWrapper;
this.consumers = consumers;
}

@@ -69,7 +71,7 @@ public class AppSettingsLoaderImpl implements AppSettingsLoader {
// supports decryption of values, so it must be used when values
// are accessed
Props props = new Props(p);
completeDefaults(props);
new ProcessProperties(serviceLoaderWrapper).completeDefaults(props);
Arrays.stream(consumers).forEach(c -> c.accept(props));

return new AppSettingsImpl(props);

+ 6
- 1
server/sonar-main/src/test/java/org/sonar/application/command/CommandFactoryImplTest.java View File

@@ -20,6 +20,7 @@
package org.sonar.application.command;

import ch.qos.logback.classic.spi.ILoggingEvent;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
@@ -33,6 +34,7 @@ import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import org.sonar.application.es.EsInstallation;
import org.sonar.application.logging.ListAppender;
import org.sonar.core.extension.ServiceLoaderWrapper;
import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
@@ -40,6 +42,7 @@ import org.sonar.process.System2;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class CommandFactoryImplTest {
@@ -320,7 +323,9 @@ public class CommandFactoryImplTest {
p.putAll(userProps);

Props props = new Props(p);
ProcessProperties.completeDefaults(props);
ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of());
new ProcessProperties(serviceLoaderWrapper).completeDefaults(props);
return new CommandFactoryImpl(props, tempDir, system2, javaVersion);
}


+ 18
- 6
server/sonar-main/src/test/java/org/sonar/application/config/AppSettingsLoaderImplTest.java View File

@@ -19,15 +19,20 @@
*/
package org.sonar.application.config;

import com.google.common.collect.ImmutableSet;
import java.io.File;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.core.extension.ServiceLoaderWrapper;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.MapEntry.entry;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class AppSettingsLoaderImplTest {

@@ -36,13 +41,20 @@ public class AppSettingsLoaderImplTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();

private ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);

@Before
public void setup() {
when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of());
}

@Test
public void load_properties_from_file() throws Exception {
File homeDir = temp.newFolder();
File propsFile = new File(homeDir, "conf/sonar.properties");
FileUtils.write(propsFile, "foo=bar");

AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[0], homeDir);
AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[0], homeDir, serviceLoaderWrapper);
AppSettings settings = underTest.load();

assertThat(settings.getProps().rawProperties()).contains(entry("foo", "bar"));
@@ -53,7 +65,7 @@ public class AppSettingsLoaderImplTest {
File homeDir = temp.newFolder();
File propsFileAsDir = new File(homeDir, "conf/sonar.properties");
FileUtils.forceMkdir(propsFileAsDir);
AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[0], homeDir);
AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[0], homeDir, serviceLoaderWrapper);

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Cannot open file " + propsFileAsDir.getAbsolutePath());
@@ -65,7 +77,7 @@ public class AppSettingsLoaderImplTest {
public void file_is_not_loaded_if_it_does_not_exist() throws Exception {
File homeDir = temp.newFolder();

AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[0], homeDir);
AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[0], homeDir, serviceLoaderWrapper);
AppSettings settings = underTest.load();

// no failure, file is ignored
@@ -76,7 +88,7 @@ public class AppSettingsLoaderImplTest {
public void command_line_arguments_are_included_to_settings() throws Exception {
File homeDir = temp.newFolder();

AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[] {"-Dsonar.foo=bar", "-Dhello=world"}, homeDir);
AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[] {"-Dsonar.foo=bar", "-Dhello=world"}, homeDir, serviceLoaderWrapper);
AppSettings settings = underTest.load();

assertThat(settings.getProps().rawProperties())
@@ -90,7 +102,7 @@ public class AppSettingsLoaderImplTest {
File propsFile = new File(homeDir, "conf/sonar.properties");
FileUtils.write(propsFile, "sonar.foo=file");

AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[]{"-Dsonar.foo=cli"}, homeDir);
AppSettingsLoaderImpl underTest = new AppSettingsLoaderImpl(new String[] {"-Dsonar.foo=cli"}, homeDir, serviceLoaderWrapper);
AppSettings settings = underTest.load();

assertThat(settings.getProps().rawProperties()).contains(entry("sonar.foo", "cli"));
@@ -98,7 +110,7 @@ public class AppSettingsLoaderImplTest {

@Test
public void detectHomeDir_returns_existing_dir() {
assertThat(new AppSettingsLoaderImpl(new String[0]).getHomeDir()).exists().isDirectory();
assertThat(new AppSettingsLoaderImpl(new String[0], serviceLoaderWrapper).getHomeDir()).exists().isDirectory();

}
}

+ 8
- 1
server/sonar-main/src/test/java/org/sonar/application/config/TestAppSettings.java View File

@@ -19,11 +19,16 @@
*/
package org.sonar.application.config;

import com.google.common.collect.ImmutableSet;
import java.util.Optional;
import java.util.Properties;
import org.sonar.core.extension.ServiceLoaderWrapper;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* Simple implementation of {@link AppSettings} that loads
* the default values defined by {@link ProcessProperties}.
@@ -34,7 +39,9 @@ public class TestAppSettings implements AppSettings {

public TestAppSettings() {
this.props = new Props(new Properties());
ProcessProperties.completeDefaults(this.props);
ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of());
new ProcessProperties(serviceLoaderWrapper).completeDefaults(this.props);
}

public TestAppSettings set(String key, String value) {

+ 5
- 1
server/sonar-main/src/test/java/org/sonar/application/es/EsSettingsTest.java View File

@@ -20,6 +20,7 @@
package org.sonar.application.es;

import ch.qos.logback.classic.spi.ILoggingEvent;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.IOException;
import java.util.Map;
@@ -31,6 +32,7 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.application.logging.ListAppender;
import org.sonar.core.extension.ServiceLoaderWrapper;
import org.sonar.process.ProcessProperties;
import org.sonar.process.ProcessProperties.Property;
import org.sonar.process.Props;
@@ -331,7 +333,9 @@ public class EsSettingsTest {
private Props minProps(boolean cluster) throws IOException {
File homeDir = temp.newFolder();
Props props = new Props(new Properties());
ProcessProperties.completeDefaults(props);
ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of());
new ProcessProperties(serviceLoaderWrapper).completeDefaults(props);
props.set(PATH_HOME.getKey(), homeDir.getAbsolutePath());
props.set(Property.CLUSTER_ENABLED.getKey(), Boolean.toString(cluster));
return props;

+ 2
- 1
server/sonar-process/build.gradle View File

@@ -15,7 +15,8 @@ dependencies {
compile 'com.hazelcast:hazelcast'
compile 'org.slf4j:jul-to-slf4j'
compile 'org.slf4j:slf4j-api'

compile project(':sonar-core')
compileOnly 'com.google.code.findbugs:jsr305'
compileOnly 'com.google.protobuf:protobuf-java'
compileOnly 'org.nanohttpd:nanohttpd'

+ 28
- 4
server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java View File

@@ -22,12 +22,18 @@ package org.sonar.process;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.core.extension.CoreExtension;
import org.sonar.core.extension.ServiceLoaderWrapper;

import static java.lang.String.format;

/**
* Constants shared by search, web server and app processes.
@@ -35,6 +41,8 @@ import javax.annotation.Nullable;
*/
public class ProcessProperties {

private final ServiceLoaderWrapper serviceLoaderWrapper;

public enum Property {
JDBC_URL("sonar.jdbc.url"),
JDBC_USERNAME("sonar.jdbc.username", ""),
@@ -151,11 +159,11 @@ public class ProcessProperties {
}
}

private ProcessProperties() {
// only static stuff
public ProcessProperties(ServiceLoaderWrapper serviceLoaderWrapper) {
this.serviceLoaderWrapper = serviceLoaderWrapper;
}

public static void completeDefaults(Props props) {
public void completeDefaults(Props props) {
// init string properties
for (Map.Entry<Object, Object> entry : defaults().entrySet()) {
props.setDefault(entry.getKey().toString(), entry.getValue().toString());
@@ -164,14 +172,30 @@ public class ProcessProperties {
fixPortIfZero(props, Property.SEARCH_HOST.getKey(), Property.SEARCH_PORT.getKey());
}

public static Properties defaults() {
private Properties defaults() {
Properties defaults = new Properties();
defaults.putAll(Arrays.stream(Property.values())
.filter(Property::hasDefaultValue)
.collect(Collectors.toMap(Property::getKey, Property::getDefaultValue)));
defaults.putAll(loadDefaultsFromExtensions());
return defaults;
}

private Map<String, String> loadDefaultsFromExtensions() {
Map<String, String> propertyDefaults = new HashMap<>();
Set<CoreExtension> extensions = serviceLoaderWrapper.load();
for (CoreExtension ext : extensions) {
for (Map.Entry<String, String> property : ext.getExtensionProperties().entrySet()) {
if (propertyDefaults.put(property.getKey(), property.getValue()) != null) {
throw new IllegalStateException(format("Configuration error: property definition named '%s' found in multiple extensions.",
property.getKey()));
}
}
}

return propertyDefaults;
}

private static void fixPortIfZero(Props props, String addressPropertyKey, String portPropertyKey) {
String port = props.value(portPropertyKey);
if ("0".equals(port)) {

+ 106
- 9
server/sonar-process/src/test/java/org/sonar/process/ProcessPropertiesTest.java View File

@@ -19,19 +19,34 @@
*/
package org.sonar.process;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.net.InetAddress;
import java.util.Map;
import java.util.Properties;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.test.TestUtils;
import org.junit.rules.ExpectedException;
import org.sonar.core.extension.CoreExtension;
import org.sonar.core.extension.ServiceLoaderWrapper;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ProcessPropertiesTest {

private ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
private ProcessProperties processProperties = new ProcessProperties(serviceLoaderWrapper);

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void completeDefaults_adds_default_values() {
Props props = new Props(new Properties());
ProcessProperties.completeDefaults(props);

processProperties.completeDefaults(props);

assertThat(props.value("sonar.search.javaOpts")).contains("-Xmx");
assertThat(props.valueAsInt("sonar.jdbc.maxActive")).isEqualTo(60);
@@ -44,21 +59,22 @@ public class ProcessPropertiesTest {
Properties p = new Properties();
p.setProperty("sonar.jdbc.username", "angela");
Props props = new Props(p);
ProcessProperties.completeDefaults(props);

processProperties.completeDefaults(props);

assertThat(props.value("sonar.jdbc.username")).isEqualTo("angela");
}

@Test
public void completeDefaults_set_default_elasticsearch_port_and_bind_address() throws Exception{
public void completeDefaults_set_default_elasticsearch_port_and_bind_address() throws Exception {
Properties p = new Properties();
Props props = new Props(p);
ProcessProperties.completeDefaults(props);

processProperties.completeDefaults(props);

String address = props.value("sonar.search.host");
assertThat(address).isNotEmpty();
assertThat(InetAddress.getByName(address).isLoopbackAddress()).isTrue();

assertThat(props.valueAsInt("sonar.search.port")).isEqualTo(9001);
}

@@ -68,12 +84,93 @@ public class ProcessPropertiesTest {
p.setProperty("sonar.search.port", "0");
Props props = new Props(p);

ProcessProperties.completeDefaults(props);
processProperties.completeDefaults(props);

assertThat(props.valueAsInt("sonar.search.port")).isGreaterThan(0);
}

@Test
public void private_constructor() {
assertThat(TestUtils.hasOnlyPrivateConstructors(ProcessProperties.class)).isTrue();
public void defaults_loads_properties_defaults_from_base_and_extensions() {
Props p = new Props(new Properties());
when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of(new FakeExtension1(), new FakeExtension3()));

processProperties.completeDefaults(p);

assertThat(p.value("sonar.some.property")).isEqualTo("1");
assertThat(p.value("sonar.some.property2")).isEqualTo("455");
assertThat(p.value("sonar.some.property4")).isEqualTo("abc");
assertThat(p.value("sonar.some.property5")).isEqualTo("def");
assertThat(p.value("sonar.some.property5")).isEqualTo("def");
assertThat(p.value("sonar.search.port")).isEqualTo("9001");
}

@Test
public void defaults_throws_exception_on_same_property_defined_more_than_once_in_extensions() {
Props p = new Props(new Properties());
when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of(new FakeExtension1(), new FakeExtension2()));
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Configuration error: property definition named 'sonar.some.property2' found in multiple extensions.");

processProperties.completeDefaults(p);
}

private class FakeExtension1 implements CoreExtension {

@Override
public String getName() {
return "fakeExt1";
}

@Override
public void load(Context context) {
// do nothing
}

@Override
public Map<String, String> getExtensionProperties() {
return ImmutableMap.of(
"sonar.some.property", "1",
"sonar.some.property2", "455");
}
}

private class FakeExtension2 implements CoreExtension {

@Override
public String getName() {
return "fakeExt2";
}

@Override
public void load(Context context) {
// do nothing
}

@Override
public Map<String, String> getExtensionProperties() {
return ImmutableMap.of(
"sonar.some.property2", "5435",
"sonar.some.property3", "32131");
}
}

private class FakeExtension3 implements CoreExtension {

@Override
public String getName() {
return "fakeExt3";
}

@Override
public void load(Context context) {
// do nothing
}

@Override
public Map<String, String> getExtensionProperties() {
return ImmutableMap.of(
"sonar.some.property4", "abc",
"sonar.some.property5", "def");
}
}
}

+ 17
- 0
sonar-application/build.gradle View File

@@ -1,3 +1,5 @@
import org.apache.tools.ant.filters.ReplaceTokens

sonarqube {
properties {
property 'sonar.projectName', "${projectTitle} :: Application"
@@ -92,6 +94,7 @@ task zip(type: Zip, dependsOn: [configurations.compile]) {

into("${archiveDir}/") {
from file('src/main/assembly')
exclude 'conf/sonar.properties'
exclude 'elasticsearch-patch'
// elasticsearch script will be replaced by patched version below
exclude 'elasticsearch/bin/elasticsearch'
@@ -125,6 +128,20 @@ task zip(type: Zip, dependsOn: [configurations.compile]) {
exclude 'elasticsearch/modules/tribe/**'
exclude 'elasticsearch/modules/x-pack-*/**'
}

into("${archiveDir}/conf/") {
from file('src/main/assembly/conf/sonar.properties')
filter(ReplaceTokens, tokens: [
'searchDefaultHeapSize': '512MB',
'searchJavaOpts' : '-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError',
'ceDefaultHeapSize' : '512MB',
'ceJavaOpts' : '-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError',
'webDefaultHeapSize' : '512MB',
'webJavaOpts' : '-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError'
])
}
into("${archiveDir}/elasticsearch/") {
from file('src/main/assembly/elasticsearch-patch')
include 'bin/elasticsearch'

+ 6
- 6
sonar-application/src/main/assembly/conf/sonar.properties View File

@@ -84,7 +84,7 @@

#--------------------------------------------------------------------------------------------------
# WEB SERVER
# Web server is executed in a dedicated Java process. By default heap size is 512Mb.
# Web server is executed in a dedicated Java process. By default heap size is @webDefaultHeapSize@.
# Use the following property to customize JVM options.
# Recommendations:
#
@@ -96,7 +96,7 @@
# -Djava.security.egd=file:/dev/./urandom is an option to resolve the problem.
# See https://wiki.apache.org/tomcat/HowTo/FasterStartUp#Entropy_Source
#
#sonar.web.javaOpts=-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError
#sonar.web.javaOpts=@webJavaOpts@

# Same as previous property, but allows to not repeat all other settings like -Xmx
#sonar.web.javaAdditionalOpts=
@@ -238,7 +238,7 @@
#--------------------------------------------------------------------------------------------------
# COMPUTE ENGINE
# The Compute Engine is responsible for processing background tasks.
# Compute Engine is executed in a dedicated Java process. Default heap size is 512Mb.
# Compute Engine is executed in a dedicated Java process. Default heap size is @ceDefaultHeapSize@.
# Use the following property to customize JVM options.
# Recommendations:
#
@@ -246,7 +246,7 @@
# is not enabled by default on your environment:
# http://docs.oracle.com/javase/8/docs/technotes/guides/vm/server-class.html
#
#sonar.ce.javaOpts=-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError
#sonar.ce.javaOpts=@ceJavaOpts@

# Same as previous property, but allows to not repeat all other settings like -Xmx
#sonar.ce.javaAdditionalOpts=
@@ -255,7 +255,7 @@
#--------------------------------------------------------------------------------------------------
# ELASTICSEARCH
# Elasticsearch is used to facilitate fast and accurate information retrieval.
# It is executed in a dedicated Java process. Default heap size is 512Mb.
# It is executed in a dedicated Java process. Default heap size is @searchDefaultHeapSize@.
#
# --------------------------------------------------
# Word of caution for Linux users on 64bits systems
@@ -269,7 +269,7 @@
#

# JVM options of Elasticsearch process
#sonar.search.javaOpts=-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError
#sonar.search.javaOpts=@searchJavaOpts@

# Same as previous property, but allows to not repeat all other settings like -Xmx
#sonar.search.javaAdditionalOpts=

+ 2
- 1
sonar-application/src/main/java/org/sonar/application/App.java View File

@@ -33,6 +33,7 @@ import org.sonar.application.process.ProcessLauncher;
import org.sonar.application.process.ProcessLauncherImpl;
import org.sonar.application.process.StopRequestWatcher;
import org.sonar.application.process.StopRequestWatcherImpl;
import org.sonar.core.extension.ServiceLoaderWrapper;
import org.sonar.process.System2;
import org.sonar.process.SystemExit;

@@ -50,7 +51,7 @@ public class App {
}

public void start(String[] cliArguments) throws IOException {
AppSettingsLoader settingsLoader = new AppSettingsLoaderImpl(cliArguments);
AppSettingsLoader settingsLoader = new AppSettingsLoaderImpl(cliArguments, new ServiceLoaderWrapper());
AppSettings settings = settingsLoader.load();
// order is important - logging must be configured before any other components (AppFileSystem, ...)
AppLogging logging = new AppLogging(settings);

+ 10
- 0
sonar-core/src/main/java/org/sonar/core/extension/CoreExtension.java View File

@@ -19,7 +19,9 @@
*/
package org.sonar.core.extension;

import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import java.util.Map;
import org.sonar.api.SonarRuntime;
import org.sonar.api.config.Configuration;

@@ -51,4 +53,12 @@ public interface CoreExtension {
}

void load(Context context);

/**
* Properties with (optionally) default values defined by the extension.
* @return map of property names as keys and property default value as values
*/
default Map<String, String> getExtensionProperties() {
return ImmutableMap.of();
}
}

+ 0
- 9
sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsLoader.java View File

@@ -19,9 +19,7 @@
*/
package org.sonar.core.extension;

import com.google.common.collect.ImmutableSet;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.stream.Collectors;
import org.sonar.api.utils.log.Logger;
@@ -70,11 +68,4 @@ public class CoreExtensionsLoader {
"Multiple core extensions declare the following names: %s",
duplicatedNames.stream().sorted().collect(Collectors.joining(", ")));
}

static class ServiceLoaderWrapper {
Set<CoreExtension> load(ClassLoader classLoader) {
ServiceLoader<CoreExtension> loader = ServiceLoader.load(CoreExtension.class, classLoader);
return ImmutableSet.copyOf(loader.iterator());
}
}
}

+ 36
- 0
sonar-core/src/main/java/org/sonar/core/extension/ServiceLoaderWrapper.java View File

@@ -0,0 +1,36 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.core.extension;

import com.google.common.collect.ImmutableSet;
import java.util.ServiceLoader;
import java.util.Set;
import javax.annotation.Nullable;

public class ServiceLoaderWrapper {
public Set<CoreExtension> load(@Nullable ClassLoader classLoader) {
ServiceLoader<CoreExtension> loader = ServiceLoader.load(CoreExtension.class, classLoader);
return ImmutableSet.copyOf(loader.iterator());
}

public Set<CoreExtension> load() {
return load(null);
}
}

+ 44
- 0
sonar-core/src/test/java/org/sonar/core/extension/CoreExtensionTest.java View File

@@ -0,0 +1,44 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.core.extension;

import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class CoreExtensionTest {

private CoreExtension underTest = new CoreExtension() {
@Override
public String getName() {
return "fake";
}

@Override
public void load(Context context) {
// nothing to do here
}
};

@Test
public void getExtensionProperties_by_default_does_not_contain_any_overridden_property_defaults() {
assertThat(underTest.getExtensionProperties()).isEmpty();
}
}

+ 1
- 1
sonar-core/src/test/java/org/sonar/core/extension/CoreExtensionsLoaderTest.java View File

@@ -40,7 +40,7 @@ public class CoreExtensionsLoaderTest {
public ExpectedException expectedException = ExpectedException.none();

private CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
private CoreExtensionsLoader.ServiceLoaderWrapper serviceLoaderWrapper = mock(CoreExtensionsLoader.ServiceLoaderWrapper.class);
private ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
private CoreExtensionsLoader underTest = new CoreExtensionsLoader(coreExtensionRepository, serviceLoaderWrapper);

@Test

Loading…
Cancel
Save