aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-05-29 11:25:01 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-05-29 11:25:01 +0200
commit0cc7aa3e7a4f3e8a3838bbbfb970aeb4775c4e9d (patch)
tree16331cc2009b399fb7632fcb3d2661b8ebe10989
parentb0f14fa5862298c7296eb9cd61f6ca3de71b3d34 (diff)
downloadsonarqube-0cc7aa3e7a4f3e8a3838bbbfb970aeb4775c4e9d.tar.gz
sonarqube-0cc7aa3e7a4f3e8a3838bbbfb970aeb4775c4e9d.zip
Extract an interface from org.sonar.process.ProcessCommands
Try to stabilize StopWatcherTest when machine is slow or under pressure. More than 1 second could be spent in the creation of ProcessCommands mock.
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java3
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java9
-rw-r--r--server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java16
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java160
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java116
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java2
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/DefaultProcessCommandsTest.java (renamed from server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java)23
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java17
-rw-r--r--sonar-application/src/main/java/org/sonar/application/App.java3
9 files changed, 210 insertions, 139 deletions
diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java
index 1e3ee06648e..390746bca59 100644
--- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java
+++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java
@@ -21,6 +21,7 @@ package org.sonar.process.monitor;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;
+import org.sonar.process.DefaultProcessCommands;
import org.sonar.process.ProcessCommands;
import org.sonar.process.ProcessEntryPoint;
import org.sonar.process.ProcessUtils;
@@ -45,7 +46,7 @@ public class JavaProcessLauncher {
Process process = null;
try {
// cleanup existing monitor files
- ProcessCommands commands = new ProcessCommands(command.getTempDir(), command.getProcessIndex());
+ ProcessCommands commands = new DefaultProcessCommands(command.getTempDir(), command.getProcessIndex());
ProcessBuilder processBuilder = create(command);
LoggerFactory.getLogger(getClass()).info("Launch process[{}]: {}",
diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java
index df3d53518ee..dd0ca58ba0a 100644
--- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java
+++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java
@@ -19,15 +19,14 @@
*/
package org.sonar.process.monitor;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.slf4j.LoggerFactory;
import org.sonar.process.Lifecycle;
import org.sonar.process.Lifecycle.State;
import org.sonar.process.ProcessCommands;
import org.sonar.process.SystemExit;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
public class Monitor {
private final List<ProcessRef> processes = new CopyOnWriteArrayList<>();
@@ -165,8 +164,8 @@ public class Monitor {
}
public static int getNextProcessId() {
- if (nextProcessId >= ProcessCommands.getMaxProcesses()) {
- throw new IllegalStateException("The maximum number of processes launched has been reached " + ProcessCommands.getMaxProcesses());
+ if (nextProcessId >= ProcessCommands.MAX_PROCESSES) {
+ throw new IllegalStateException("The maximum number of processes launched has been reached " + ProcessCommands.MAX_PROCESSES);
}
return nextProcessId++;
}
diff --git a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java
index 57e3478162c..00ae573ed6a 100644
--- a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java
+++ b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java
@@ -20,6 +20,11 @@
package org.sonar.process.monitor;
import com.github.kevinsawicki.http.HttpRequest;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.BeforeClass;
@@ -27,17 +32,11 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.Timeout;
-import org.sonar.process.NetworkUtils;
import org.sonar.process.Lifecycle.State;
+import org.sonar.process.NetworkUtils;
import org.sonar.process.ProcessCommands;
import org.sonar.process.SystemExit;
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
@@ -211,7 +210,8 @@ public class MonitorTest {
@Test
public void test_too_many_processes() {
- while (Monitor.getNextProcessId() < ProcessCommands.getMaxProcesses() - 1) {}
+ while (Monitor.getNextProcessId() < ProcessCommands.MAX_PROCESSES - 1) {
+ }
try {
newDefaultMonitor();
} catch (IllegalStateException e) {
diff --git a/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java
new file mode 100644
index 00000000000..f2992523f35
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java
@@ -0,0 +1,160 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.process;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Process inter-communication to :
+ * <ul>
+ * <li>share status of child process</li>
+ * <li>stop child process</li>
+ * </ul>
+ *
+ * <p/>
+ * It relies on files shared by both processes. Following alternatives were considered but not selected :
+ * <ul>
+ * <li>JMX beans over RMI: network issues (mostly because of Java reverse-DNS) + requires to configure and open a new port</li>
+ * <li>simple socket protocol: same drawbacks are RMI connection</li>
+ * <li>java.lang.Process#destroy(): shutdown hooks are not executed on some OS (mostly MSWindows)</li>
+ * <li>execute OS-specific commands (for instance kill on *nix): OS-specific, so hell to support. Moreover how to get identify a process ?</li>
+ * </ul>
+ */
+public class DefaultProcessCommands implements ProcessCommands {
+
+ /**
+ * The ByteBuffer will contains :
+ * <ul>
+ * <li>First byte will contains 0x00 until stop command is issued = 0xFF</li>
+ * <li>Then each 10 bytes will be reserved for each process</li>
+ * </ul>
+ *
+ * Description of ten bytes of each process :
+ * <ul>
+ * <li>First byte will contains the state 0x00 until READY 0x01</li>
+ * <li>The second byte will contains the request for stopping 0x00 or STOP (0xFF)</li>
+ * <li>The next 8 bytes contains a long (System.currentTimeInMillis for ping)</li>
+ * </ul>
+ */
+ final MappedByteBuffer mappedByteBuffer;
+ private final RandomAccessFile sharedMemory;
+ private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 8;
+
+ // With this shared memory we can handle up to MAX_PROCESSES processes
+ private static final int MAX_SHARED_MEMORY = BYTE_LENGTH_FOR_ONE_PROCESS * MAX_PROCESSES;
+
+ public static final byte STOP = (byte) 0xFF;
+ public static final byte READY = (byte) 0x01;
+ public static final byte EMPTY = (byte) 0x00;
+
+ private int processNumber;
+
+ public DefaultProcessCommands(File directory, int processNumber) {
+ // processNumber should not excess MAX_PROCESSES and must not be below -1
+ assert processNumber <= MAX_PROCESSES : "Incorrect process number";
+ assert processNumber >= -1 : "Incorrect process number";
+
+ this.processNumber = processNumber;
+ if (!directory.isDirectory() || !directory.exists()) {
+ throw new IllegalArgumentException("Not a valid directory: " + directory);
+ }
+
+ try {
+ sharedMemory = new RandomAccessFile(new File(directory, "sharedmemory"), "rw");
+ mappedByteBuffer = sharedMemory.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, MAX_SHARED_MEMORY);
+ cleanData();
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Unable to create shared memory : ", e);
+ }
+ }
+
+ @Override
+ public boolean isReady() {
+ return canBeMonitored() && mappedByteBuffer.get(offset()) == READY;
+ }
+
+ /**
+ * To be executed by child process to declare that it's ready
+ */
+ @Override
+ public void setReady() {
+ if (canBeMonitored()) {
+ mappedByteBuffer.put(offset(), READY);
+ }
+ }
+
+ @Override
+ public void ping() {
+ if (canBeMonitored()) {
+ mappedByteBuffer.putLong(2 + offset(), System.currentTimeMillis());
+ }
+ }
+
+ @Override
+ public long getLastPing() {
+ if (canBeMonitored()) {
+ return mappedByteBuffer.getLong(2 + offset());
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * To be executed by monitor process to ask for child process termination
+ */
+ @Override
+ public void askForStop() {
+ mappedByteBuffer.put(offset() + 1, STOP);
+ }
+
+ @Override
+ public boolean askedForStop() {
+ return mappedByteBuffer.get(offset() + 1) == STOP;
+ }
+
+ @Override
+ public void endWatch() {
+ IOUtils.closeQuietly(sharedMemory);
+ }
+
+ int offset() {
+ return BYTE_LENGTH_FOR_ONE_PROCESS * processNumber;
+ }
+
+ private boolean canBeMonitored() {
+ boolean result = processNumber >= 0 && processNumber < MAX_PROCESSES;
+ if (!result) {
+ LoggerFactory.getLogger(getClass()).info("This process cannot be monitored. Process Id : [{}]", processNumber);
+ }
+ return result;
+ }
+
+ private void cleanData() {
+ for (int i = 0; i < BYTE_LENGTH_FOR_ONE_PROCESS; i++) {
+ mappedByteBuffer.put(offset() + i, EMPTY);
+ }
+ }
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
index d697f542f32..8c027d45c7c 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
@@ -19,15 +19,6 @@
*/
package org.sonar.process;
-import org.apache.commons.io.IOUtils;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-
/**
* Process inter-communication to :
* <ul>
@@ -44,116 +35,27 @@ import java.nio.channels.FileChannel;
* <li>execute OS-specific commands (for instance kill on *nix): OS-specific, so hell to support. Moreover how to get identify a process ?</li>
* </ul>
*/
-public class ProcessCommands {
-
- /**
- * The ByteBuffer will contains :
- * <ul>
- * <li>First byte will contains 0x00 until stop command is issued = 0xFF</li>
- * <li>Then each 10 bytes will be reserved for each process</li>
- * </ul>
- *
- * Description of ten bytes of each process :
- * <ul>
- * <li>First byte will contains the state 0x00 until READY 0x01</li>
- * <li>The second byte will contains the request for stopping 0x00 or STOP (0xFF)</li>
- * <li>The next 8 bytes contains a long (System.currentTimeInMillis for ping)</li>
- * </ul>
- */
- final MappedByteBuffer mappedByteBuffer;
- private final RandomAccessFile sharedMemory;
- private static final int MAX_PROCESSES = 50;
- private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 8;
-
- // With this shared memory we can handle up to MAX_PROCESSES processes
- private static final int MAX_SHARED_MEMORY = BYTE_LENGTH_FOR_ONE_PROCESS * MAX_PROCESSES;
-
- public static final byte STOP = (byte) 0xFF;
- public static final byte READY = (byte) 0x01;
- public static final byte EMPTY = (byte) 0x00;
+public interface ProcessCommands {
- private int processNumber;
+ int MAX_PROCESSES = 50;
- public ProcessCommands(File directory, int processNumber) {
- // processNumber should not excess MAX_PROCESSES and must not be below -1
- assert processNumber <= MAX_PROCESSES : "Incorrect process number";
- assert processNumber >= -1 : "Incorrect process number";
-
- this.processNumber = processNumber;
- if (!directory.isDirectory() || !directory.exists()) {
- throw new IllegalArgumentException("Not a valid directory: " + directory);
- }
-
- try {
- sharedMemory = new RandomAccessFile(new File(directory, "sharedmemory"), "rw");
- mappedByteBuffer = sharedMemory.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, MAX_SHARED_MEMORY);
- cleanData();
- } catch (IOException e) {
- throw new IllegalArgumentException("Unable to create shared memory : ", e);
- }
- }
-
- public boolean isReady() {
- return canBeMonitored() && mappedByteBuffer.get(offset()) == READY;
- }
+ boolean isReady();
/**
* To be executed by child process to declare that it's ready
*/
- public void setReady() {
- if (canBeMonitored()) {
- mappedByteBuffer.put(offset(), READY);
- }
- }
+ void setReady();
- public void ping() {
- if (canBeMonitored()) {
- mappedByteBuffer.putLong(2 + offset(), System.currentTimeMillis());
- }
- }
+ void ping();
- public long getLastPing() {
- if (canBeMonitored()) {
- return mappedByteBuffer.getLong(2 + offset());
- } else {
- return -1;
- }
- }
+ long getLastPing();
/**
* To be executed by monitor process to ask for child process termination
*/
- public void askForStop() {
- mappedByteBuffer.put(offset() + 1, STOP);
- }
-
- public boolean askedForStop() {
- return mappedByteBuffer.get(offset() + 1) == STOP;
- }
-
- public void endWatch() {
- IOUtils.closeQuietly(sharedMemory);
- }
-
- int offset() {
- return BYTE_LENGTH_FOR_ONE_PROCESS * processNumber;
- }
-
- private boolean canBeMonitored() {
- boolean result = processNumber >= 0 && processNumber < MAX_PROCESSES;
- if (!result) {
- LoggerFactory.getLogger(getClass()).info("This process cannot be monitored. Process Id : [{}]", processNumber);
- }
- return result;
- }
+ void askForStop();
- private void cleanData() {
- for (int i = 0; i < BYTE_LENGTH_FOR_ONE_PROCESS; i++) {
- mappedByteBuffer.put(offset() + i, EMPTY);
- }
- }
+ boolean askedForStop();
- public static int getMaxProcesses() {
- return MAX_PROCESSES;
- }
+ void endWatch();
}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
index 49f954a16ac..19f361911cf 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
@@ -134,7 +134,7 @@ public class ProcessEntryPoint implements Stoppable {
public static ProcessEntryPoint createForArguments(String[] args) {
Props props = ConfigurationUtils.loadPropsFromCommandLineArgs(args);
- ProcessCommands commands = new ProcessCommands(
+ ProcessCommands commands = new DefaultProcessCommands(
props.nonNullValueAsFile(PROPERTY_SHARED_PATH), Integer.parseInt(props.nonNullValue(PROPERTY_PROCESS_INDEX)));
return new ProcessEntryPoint(props, new SystemExit(), commands);
}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/DefaultProcessCommandsTest.java
index aba88feb016..16bc7e558c7 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/DefaultProcessCommandsTest.java
@@ -19,18 +19,17 @@
*/
package org.sonar.process;
+import java.io.File;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import java.io.File;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
import static org.junit.Assert.fail;
-public class ProcessCommandsTest {
+public class DefaultProcessCommandsTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@@ -41,7 +40,7 @@ public class ProcessCommandsTest {
FileUtils.deleteQuietly(dir);
try {
- new ProcessCommands(dir, 1);
+ new DefaultProcessCommands(dir, 1);
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Not a valid directory: " + dir.getAbsolutePath());
@@ -52,14 +51,14 @@ public class ProcessCommandsTest {
public void child_process_update_the_mapped_memory() throws Exception {
File dir = temp.newFolder();
- ProcessCommands commands = new ProcessCommands(dir, 1);
+ DefaultProcessCommands commands = new DefaultProcessCommands(dir, 1);
assertThat(commands.isReady()).isFalse();
- assertThat(commands.mappedByteBuffer.get(commands.offset())).isEqualTo(ProcessCommands.EMPTY);
+ assertThat(commands.mappedByteBuffer.get(commands.offset())).isEqualTo(DefaultProcessCommands.EMPTY);
assertThat(commands.mappedByteBuffer.getLong(2 + commands.offset())).isEqualTo(0L);
commands.setReady();
assertThat(commands.isReady()).isTrue();
- assertThat(commands.mappedByteBuffer.get(commands.offset())).isEqualTo(ProcessCommands.READY);
+ assertThat(commands.mappedByteBuffer.get(commands.offset())).isEqualTo(DefaultProcessCommands.READY);
long currentTime = System.currentTimeMillis();
commands.ping();
@@ -70,26 +69,26 @@ public class ProcessCommandsTest {
public void ask_for_stop() throws Exception {
File dir = temp.newFolder();
- ProcessCommands commands = new ProcessCommands(dir, 1);
- assertThat(commands.mappedByteBuffer.get(commands.offset() + 1)).isNotEqualTo(ProcessCommands.STOP);
+ DefaultProcessCommands commands = new DefaultProcessCommands(dir, 1);
+ assertThat(commands.mappedByteBuffer.get(commands.offset() + 1)).isNotEqualTo(DefaultProcessCommands.STOP);
assertThat(commands.askedForStop()).isFalse();
commands.askForStop();
assertThat(commands.askedForStop()).isTrue();
- assertThat(commands.mappedByteBuffer.get(commands.offset() + 1)).isEqualTo(ProcessCommands.STOP);
+ assertThat(commands.mappedByteBuffer.get(commands.offset() + 1)).isEqualTo(DefaultProcessCommands.STOP);
}
@Test
public void test_max_processes() throws Exception {
File dir = temp.newFolder();
try {
- new ProcessCommands(dir, -2);
+ new DefaultProcessCommands(dir, -2);
failBecauseExceptionWasNotThrown(AssertionError.class);
} catch (AssertionError e) {
assertThat(e).hasMessage("Incorrect process number");
}
try {
- new ProcessCommands(dir, ProcessCommands.getMaxProcesses() + 1);
+ new DefaultProcessCommands(dir, ProcessCommands.MAX_PROCESSES + 1);
failBecauseExceptionWasNotThrown(AssertionError.class);
} catch (AssertionError e) {
assertThat(e).hasMessage("Incorrect process number");
diff --git a/server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java b/server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java
index ac045982ef7..e78d1c17b3e 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java
@@ -19,16 +19,25 @@
*/
package org.sonar.process;
+import java.util.concurrent.TimeUnit;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.Timeout;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class StopWatcherTest {
- @Test(timeout = 1000L)
+ @Rule
+ public Timeout timeout = new Timeout(1000, TimeUnit.MILLISECONDS);
+
+ @Test
public void stop_if_receive_command() throws InterruptedException {
ProcessCommands commands = mock(ProcessCommands.class);
- when(commands.askedForStop()).thenReturn(false).thenReturn(true);
+ when(commands.askedForStop()).thenReturn(false, true);
Stoppable stoppable = mock(Stoppable.class);
StopWatcher watcher = new StopWatcher(commands, stoppable, 1L);
@@ -38,7 +47,7 @@ public class StopWatcherTest {
verify(stoppable).stopAsync();
}
- @Test(timeout = 1000L)
+ @Test
public void stop_watching_on_interruption() throws InterruptedException {
ProcessCommands commands = mock(ProcessCommands.class);
when(commands.askedForStop()).thenReturn(false);
diff --git a/sonar-application/src/main/java/org/sonar/application/App.java b/sonar-application/src/main/java/org/sonar/application/App.java
index 26130401dac..9547d505895 100644
--- a/sonar-application/src/main/java/org/sonar/application/App.java
+++ b/sonar-application/src/main/java/org/sonar/application/App.java
@@ -21,6 +21,7 @@ package org.sonar.application;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
+import org.sonar.process.DefaultProcessCommands;
import org.sonar.process.MinimumViableSystem;
import org.sonar.process.ProcessCommands;
import org.sonar.process.ProcessProperties;
@@ -54,7 +55,7 @@ public class App implements Stoppable {
public void start(Props props) {
if (props.valueAsBoolean(ProcessProperties.ENABLE_STOP_COMMAND, false)) {
File tempDir = props.nonNullValueAsFile(ProcessProperties.PATH_TEMP);
- ProcessCommands commands = new ProcessCommands(tempDir, 0);
+ ProcessCommands commands = new DefaultProcessCommands(tempDir, 0);
stopWatcher = new StopWatcher(commands, this);
stopWatcher.start();
}