aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-runner-dist/src/main/java/org/sonar/runner/Main.java28
-rw-r--r--sonar-runner-dist/src/main/java/org/sonar/runner/Shutdown.java92
-rw-r--r--sonar-runner-dist/src/test/java/org/sonar/runner/MainTest.java3
-rw-r--r--sonar-runner-dist/src/test/java/org/sonar/runner/ShutdownTest.java78
4 files changed, 190 insertions, 11 deletions
diff --git a/sonar-runner-dist/src/main/java/org/sonar/runner/Main.java b/sonar-runner-dist/src/main/java/org/sonar/runner/Main.java
index d991dc2..ea472d1 100644
--- a/sonar-runner-dist/src/main/java/org/sonar/runner/Main.java
+++ b/sonar-runner-dist/src/main/java/org/sonar/runner/Main.java
@@ -43,15 +43,15 @@ import org.sonar.runner.impl.Logs;
*/
public class Main {
- private final Exit exit;
+ private final Shutdown shutdown;
private final Cli cli;
private final Conf conf;
private final RunnerFactory runnerFactory;
private Runner<?> runner;
private BufferedReader inputReader;
- Main(Exit exit, Cli cli, Conf conf, RunnerFactory runnerFactory) {
- this.exit = exit;
+ Main(Shutdown shutdown, Cli cli, Conf conf, RunnerFactory runnerFactory) {
+ this.shutdown = shutdown;
this.cli = cli;
this.conf = conf;
this.runnerFactory = runnerFactory;
@@ -59,9 +59,10 @@ public class Main {
public static void main(String[] args) {
Exit exit = new Exit();
+ Shutdown shutdown = new Shutdown(exit);
Cli cli = new Cli(exit).parse(args);
cli.verify();
- Main main = new Main(exit, cli, new Conf(cli), new RunnerFactory());
+ Main main = new Main(shutdown, cli, new Conf(cli), new RunnerFactory());
main.execute();
}
@@ -84,17 +85,17 @@ public class Main {
} catch (Exception e) {
displayExecutionResult(stats, "FAILURE");
showError("Error during Sonar runner execution", e, cli.isDisplayStackTrace());
- exit.exit(Exit.ERROR);
+ shutdown.exit(Exit.ERROR);
}
runner.stop();
- exit.exit(Exit.SUCCESS);
+ shutdown.exit(Exit.SUCCESS);
}
private void init(Properties p) throws IOException {
SystemInfo.print();
if (cli.isDisplayVersionOnly()) {
- exit.exit(Exit.SUCCESS);
+ shutdown.exit(Exit.SUCCESS);
}
if (cli.isDisplayStackTrace()) {
@@ -113,9 +114,18 @@ public class Main {
if (inputReader == null) {
inputReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
}
+
+ shutdown.signalReady(true);
+ if(shutdown.shouldExit()) {
+ //exit before displaying message
+ return false;
+ }
+
Logs.info("<Press enter to restart analysis>");
-
- return inputReader.readLine() != null;
+ String line = inputReader.readLine();
+ shutdown.signalReady(false);
+
+ return line != null;
}
private static void displayExecutionResult(Stats stats, String resultMsg) {
diff --git a/sonar-runner-dist/src/main/java/org/sonar/runner/Shutdown.java b/sonar-runner-dist/src/main/java/org/sonar/runner/Shutdown.java
new file mode 100644
index 0000000..70ec898
--- /dev/null
+++ b/sonar-runner-dist/src/main/java/org/sonar/runner/Shutdown.java
@@ -0,0 +1,92 @@
+/*
+ * SonarQube Runner - Distribution
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * 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 02
+ */
+package org.sonar.runner;
+
+class Shutdown {
+ static final int SUCCESS = 0;
+ static final int ERROR = 1;
+ private static final long DEFAULT_MAX_WAIT = 10_000;
+
+ private long maxWait;
+ ShutdownHook hook = new ShutdownHook();
+ private boolean isReady = false;
+ private boolean exiting = false;
+ private Object lock = new Object();
+ private Exit exit;
+ private Thread t;
+
+ Shutdown(Exit exit) {
+ this(exit, DEFAULT_MAX_WAIT);
+ }
+
+ Shutdown(Exit exit, long maxWait) {
+ this.maxWait = maxWait;
+ this.exit = exit;
+ Runtime.getRuntime().addShutdownHook(hook);
+ }
+
+ void exit(int status) {
+ synchronized (lock) {
+ signalReady(true);
+ }
+ exit.exit(status);
+ }
+
+ void signalReady(boolean ready) {
+ synchronized (lock) {
+ System.out.println("READY: " + ready);
+ this.isReady = ready;
+ lock.notifyAll();
+ }
+ }
+
+ boolean shouldExit() {
+ synchronized (lock) {
+ return exiting;
+ }
+ }
+
+ class ShutdownHook extends Thread {
+ private ShutdownHook() {
+ this.setName("shutdown-hook");
+ }
+
+ @Override
+ public void run() {
+ long startTime = System.currentTimeMillis();
+ synchronized (lock) {
+ exiting = true;
+
+ while (!isReady) {
+ long waitTime = startTime + maxWait - System.currentTimeMillis();
+ if (waitTime <= 0) {
+ break;
+ }
+
+ try {
+ lock.wait(waitTime);
+ } catch (InterruptedException e) {
+ // continue
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sonar-runner-dist/src/test/java/org/sonar/runner/MainTest.java b/sonar-runner-dist/src/test/java/org/sonar/runner/MainTest.java
index 773632d..7b7e019 100644
--- a/sonar-runner-dist/src/test/java/org/sonar/runner/MainTest.java
+++ b/sonar-runner-dist/src/test/java/org/sonar/runner/MainTest.java
@@ -30,7 +30,6 @@ import org.sonar.runner.api.Runner;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
@@ -44,7 +43,7 @@ import static org.mockito.Mockito.when;
public class MainTest {
@Mock
- private Exit exit;
+ private Shutdown exit;
@Mock
private Cli cli;
@Mock
diff --git a/sonar-runner-dist/src/test/java/org/sonar/runner/ShutdownTest.java b/sonar-runner-dist/src/test/java/org/sonar/runner/ShutdownTest.java
new file mode 100644
index 0000000..9de7f4c
--- /dev/null
+++ b/sonar-runner-dist/src/test/java/org/sonar/runner/ShutdownTest.java
@@ -0,0 +1,78 @@
+/*
+ * SonarQube Runner - Distribution
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * 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 02
+ */
+package org.sonar.runner;
+
+import static org.mockito.Mockito.verify;
+import static org.fest.assertions.Assertions.assertThat;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Mock;
+import org.junit.Test;
+import org.junit.Before;
+
+public class ShutdownTest {
+ @Mock
+ private Exit exit;
+ private Shutdown shutdown;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ shutdown = new Shutdown(exit);
+ }
+
+ @Test
+ public void testShutdown() {
+ shutdown.exit(3);
+ verify(exit).exit(3);
+ }
+
+ @Test(timeout = 60_000)
+ public void testWaitReady() throws InterruptedException {
+ shutdown = new Shutdown(exit, 100_000);
+ shutdown.signalReady(false);
+ assertThat(shutdown.shouldExit()).isFalse();
+
+ Thread t = new HookCaller();
+ t.start();
+ Thread.sleep(1000);
+
+ assertThat(t.isAlive()).isTrue();
+ assertThat(shutdown.shouldExit()).isTrue();
+
+ shutdown.signalReady(true);
+ t.join();
+ }
+
+ @Test(timeout = 60_000)
+ public void testTimeout() throws InterruptedException {
+ shutdown = new Shutdown(exit, 0);
+
+ Thread t = new HookCaller();
+ t.start();
+ t.join();
+ }
+
+ private class HookCaller extends Thread {
+ @Override
+ public void run() {
+ shutdown.hook.run();
+ }
+ }
+}