diff options
author | Stephane Gamard <stephane.gamard@searchbox.com> | 2014-07-24 11:58:00 +0200 |
---|---|---|
committer | Stephane Gamard <stephane.gamard@searchbox.com> | 2014-07-24 11:58:33 +0200 |
commit | 46461efc7d8a0eb23cd1019ed066c5b97b203197 (patch) | |
tree | cef3ec404a852e830b4c2883147f311d3a8d4e5f /sonar-application/src | |
parent | 128427dc9d9e76369ec5db3702b345148949dc8e (diff) | |
download | sonarqube-46461efc7d8a0eb23cd1019ed066c5b97b203197.tar.gz sonarqube-46461efc7d8a0eb23cd1019ed066c5b97b203197.zip |
SONAR-4898 - Added JMX registration to StartServer and base test
Diffstat (limited to 'sonar-application/src')
4 files changed, 135 insertions, 10 deletions
diff --git a/sonar-application/src/main/java/org/sonar/application/Installation.java b/sonar-application/src/main/java/org/sonar/application/Installation.java index fbc86ec973a..2705a3d58fe 100644 --- a/sonar-application/src/main/java/org/sonar/application/Installation.java +++ b/sonar-application/src/main/java/org/sonar/application/Installation.java @@ -43,8 +43,7 @@ public class Installation { Installation() throws URISyntaxException, IOException { // home dir guessed with location of lib/sonar-application.jar - File appJar = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()); - homeDir = appJar.getParentFile().getParentFile(); + homeDir = detectHomeDir(); props = initProps(homeDir); DefaultSettings.initDefaults(props); @@ -56,6 +55,11 @@ public class Installation { this.logsDir = initExistingDir("sonar.path.logs", "logs"); } + public File detectHomeDir() throws URISyntaxException { + File appJar = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()); + return appJar.getParentFile().getParentFile(); + } + /** * Load conf/sonar.properties */ diff --git a/sonar-application/src/main/java/org/sonar/application/StartServer.java b/sonar-application/src/main/java/org/sonar/application/StartServer.java index 84d83783aaf..ebdd4e7fa02 100644 --- a/sonar-application/src/main/java/org/sonar/application/StartServer.java +++ b/sonar-application/src/main/java/org/sonar/application/StartServer.java @@ -19,14 +19,26 @@ */ package org.sonar.application; +import com.google.common.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.process.Monitor; +import org.sonar.process.Process; +import org.sonar.process.ProcessMXBean; import org.sonar.process.ProcessWrapper; import javax.annotation.Nullable; +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.NotCompliantMBeanException; +import java.lang.management.ManagementFactory; -public class StartServer { +public class StartServer implements ProcessMXBean { + + static final String PROCESS_NAME = "SonarQube"; + + private final Installation installation; private Monitor monitor; private ProcessWrapper elasticsearch; private ProcessWrapper server; @@ -34,20 +46,40 @@ public class StartServer { private static Logger LOGGER = LoggerFactory.getLogger(StartServer.class); public StartServer() throws Exception { - Installation installation = new Installation(); + this(new Installation()); + } + + @VisibleForTesting + StartServer(Installation installation) throws Exception { + this.installation = installation; Thread shutdownHook = new Thread(new Runnable() { @Override public void run() { LOGGER.info("JVM Shutdown start"); - stop(); + terminate(); LOGGER.info("JVM Shutdown end"); } }); Runtime.getRuntime().addShutdownHook(shutdownHook); + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + try { + mbeanServer.registerMBean(this, Process.objectNameFor(PROCESS_NAME)); + } catch (InstanceAlreadyExistsException e) { + throw new IllegalStateException("Process already exists in current JVM", e); + } catch (MBeanRegistrationException e) { + throw new IllegalStateException("Could not register process as MBean", e); + } catch (NotCompliantMBeanException e) { + throw new IllegalStateException("Process is not a compliant MBean", e); + } + monitor = new Monitor(); + } + + private void start(){ + elasticsearch = new ProcessWrapper("ES") .setWorkDir(installation.homeDir()) .setJmxPort(Integer.parseInt(installation.prop(DefaultSettings.ES_JMX_PORT_KEY))) @@ -81,14 +113,19 @@ public class StartServer { monitor.registerProcess(server); monitor.start(); + try { - monitor.join(); + try { + monitor.join(); + } catch (InterruptedException e) { + LOGGER.info("Monitor interrupted. Shutting down..."); + } } finally { - stop(); + terminate(); } } - public void stop() { + public void terminate() { LOGGER.debug("StartServer::stop() START"); if (monitor != null) { LOGGER.trace("StartServer::stop() STOP MONITOR"); @@ -111,12 +148,22 @@ public class StartServer { try { process.join(); } catch (InterruptedException e) { - // TODO + LOGGER.warn("Process '{}' did not gracefully shutdown.", process.getName()); } } } public static void main(String[] args) throws Exception { - new StartServer(); + new StartServer().start(); + } + + @Override + public boolean isReady() { + return monitor.isAlive(); + } + + @Override + public long ping() { + return System.currentTimeMillis(); } } diff --git a/sonar-application/src/test/java/org/sonar/application/StartServerTest.java b/sonar-application/src/test/java/org/sonar/application/StartServerTest.java new file mode 100644 index 00000000000..1f3fa455bc1 --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/StartServerTest.java @@ -0,0 +1,74 @@ +package org.sonar.application; + +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.process.Process; + +import javax.management.MBeanServer; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import java.io.File; +import java.lang.management.ManagementFactory; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +public class StartServerTest { + + @Rule + public TemporaryFolder sonarHome = new TemporaryFolder(); + + @Before + public void setUp() throws Exception { + sonarHome.create(); + FileUtils.copyURLToFile(this.getClass().getClassLoader().getResource("conf/"), + new File(sonarHome.getRoot().getAbsolutePath(), "conf")); + } + + @After + public void tearDown() throws Exception { + sonarHome.delete(); + } + + @Test + public void should_register_mbean() throws Exception { + + Installation installation = mock(Installation.class); + when(installation.detectHomeDir()).thenReturn(sonarHome.getRoot()); + + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + + StartServer server = new StartServer(installation); + + // 0 Can have a valid ObjectName + assertThat(server).isNotNull(); + + // 1 assert that process MBean is registered + ObjectName serverObjectName = Process.objectNameFor(StartServer.PROCESS_NAME); + assertThat(mbeanServer.isRegistered(serverObjectName)).isTrue(); + + ObjectInstance serverMXBean = mbeanServer.getObjectInstance(serverObjectName); + + + System.out.println("serverMXBean.getClassName() = " + serverMXBean.getClassName()); + +// Class<?> processClass = serverMXBean.getClassName(); +// +// Method method = +// Reflection.invoke(serverMXBean, "ping", Long.class); +// +// // 2 assert that we cannot make another Process in the same JVM +// try { +// process = new TestProcess(props); +// fail(); +// } catch (IllegalStateException e) { +// assertThat(e.getMessage()).isEqualTo("Process already exists in current JVM"); +// } + } +}
\ No newline at end of file diff --git a/sonar-application/src/test/resources/conf/sonar.properties b/sonar-application/src/test/resources/conf/sonar.properties new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sonar-application/src/test/resources/conf/sonar.properties |