From: Simon Brandhof Date: Fri, 29 May 2015 09:25:01 +0000 (+0200) Subject: Extract an interface from org.sonar.process.ProcessCommands X-Git-Tag: 5.2-RC1~1780 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=0cc7aa3e7a4f3e8a3838bbbfb970aeb4775c4e9d;p=sonarqube.git 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. --- 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 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 : + * + * + *

+ * It relies on files shared by both processes. Following alternatives were considered but not selected : + *

+ */ +public class DefaultProcessCommands implements ProcessCommands { + + /** + * The ByteBuffer will contains : + * + * + * Description of ten bytes of each process : + * + */ + 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 : * */ -public class ProcessCommands { - - /** - * The ByteBuffer will contains : - * - * - * Description of ten bytes of each process : - * - */ - 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/DefaultProcessCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/DefaultProcessCommandsTest.java new file mode 100644 index 00000000000..16bc7e558c7 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/DefaultProcessCommandsTest.java @@ -0,0 +1,97 @@ +/* + * 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 org.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; +import static org.junit.Assert.fail; + +public class DefaultProcessCommandsTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void fail_to_init_if_dir_does_not_exist() throws Exception { + File dir = temp.newFolder(); + FileUtils.deleteQuietly(dir); + + try { + new DefaultProcessCommands(dir, 1); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Not a valid directory: " + dir.getAbsolutePath()); + } + } + + @Test + public void child_process_update_the_mapped_memory() throws Exception { + File dir = temp.newFolder(); + + DefaultProcessCommands commands = new DefaultProcessCommands(dir, 1); + assertThat(commands.isReady()).isFalse(); + 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(DefaultProcessCommands.READY); + + long currentTime = System.currentTimeMillis(); + commands.ping(); + assertThat(commands.mappedByteBuffer.getLong(2 + commands.offset())).isGreaterThanOrEqualTo(currentTime); + } + + @Test + public void ask_for_stop() throws Exception { + File dir = temp.newFolder(); + + 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(DefaultProcessCommands.STOP); + } + + @Test + public void test_max_processes() throws Exception { + File dir = temp.newFolder(); + try { + new DefaultProcessCommands(dir, -2); + failBecauseExceptionWasNotThrown(AssertionError.class); + } catch (AssertionError e) { + assertThat(e).hasMessage("Incorrect process number"); + } + try { + 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/ProcessCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java deleted file mode 100644 index aba88feb016..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 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 { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Test - public void fail_to_init_if_dir_does_not_exist() throws Exception { - File dir = temp.newFolder(); - FileUtils.deleteQuietly(dir); - - try { - new ProcessCommands(dir, 1); - fail(); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("Not a valid directory: " + dir.getAbsolutePath()); - } - } - - @Test - public void child_process_update_the_mapped_memory() throws Exception { - File dir = temp.newFolder(); - - ProcessCommands commands = new ProcessCommands(dir, 1); - assertThat(commands.isReady()).isFalse(); - assertThat(commands.mappedByteBuffer.get(commands.offset())).isEqualTo(ProcessCommands.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); - - long currentTime = System.currentTimeMillis(); - commands.ping(); - assertThat(commands.mappedByteBuffer.getLong(2 + commands.offset())).isGreaterThanOrEqualTo(currentTime); - } - - @Test - 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); - assertThat(commands.askedForStop()).isFalse(); - - commands.askForStop(); - assertThat(commands.askedForStop()).isTrue(); - assertThat(commands.mappedByteBuffer.get(commands.offset() + 1)).isEqualTo(ProcessCommands.STOP); - } - - @Test - public void test_max_processes() throws Exception { - File dir = temp.newFolder(); - try { - new ProcessCommands(dir, -2); - failBecauseExceptionWasNotThrown(AssertionError.class); - } catch (AssertionError e) { - assertThat(e).hasMessage("Incorrect process number"); - } - try { - new ProcessCommands(dir, ProcessCommands.getMaxProcesses() + 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(); }