Browse Source

clean shutdown

tags/2.5-rc1
Duarte Meneses 9 years ago
parent
commit
75a661f61c

+ 19
- 9
sonar-runner-dist/src/main/java/org/sonar/runner/Main.java View File

@@ -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) {

+ 92
- 0
sonar-runner-dist/src/main/java/org/sonar/runner/Shutdown.java View File

@@ -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
}
}
}
}
}
}

+ 1
- 2
sonar-runner-dist/src/test/java/org/sonar/runner/MainTest.java View File

@@ -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

+ 78
- 0
sonar-runner-dist/src/test/java/org/sonar/runner/ShutdownTest.java View File

@@ -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();
}
}
}

Loading…
Cancel
Save