import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.process.Launcher;
+import org.sonar.process.MonitorService;
+import org.sonar.process.ProcessWrapper;
import java.io.IOException;
import java.net.DatagramSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
-/**
- * @Since 4.5
- */
public class Application {
private final static Logger LOGGER = LoggerFactory.getLogger(Application.class);
public static void main(String... args) throws InterruptedException, IOException {
final ExecutorService executor = Executors.newFixedThreadPool(2);
- final Launcher sonarQube = new Launcher("SQ", systemAvailableSocket());
- final Launcher elasticsearch = new Launcher("ES", systemAvailableSocket());
+ final MonitorService monitor = new MonitorService(systemAvailableSocket());
+
+ //Create the processes
+ //final ProcessWrapper sonarQube = new ProcessWrapper("SQ", monitor);
+ final ProcessWrapper elasticsearch = null;//new ProcessWrapper("ES", monitor.getMonitoringPort());
+
+ //Register processes to monitor
+ monitor.register(elasticsearch);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
LOGGER.info("Shutting down sonar Node");
- sonarQube.interrupt();
+ //sonarQube.shutdown();
elasticsearch.interrupt();
- executor.shutdownNow();
+ executor.shutdown();
+ try {
+ executor.awaitTermination(10L, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Executing terminated", e);
+ }
}
});
- LOGGER.info("Starting SQ Node...");
- executor.submit(sonarQube);
-
- LOGGER.info("Starting ES Node...");
+ // Start our processes
+ LOGGER.info("Starting Child processes...");
executor.submit(elasticsearch);
+ //executor.submit(sonarQube);
+
+ // And monitor the activity
+ monitor.run();
- while (!executor.isTerminated()) {
- Thread.sleep(1000);
- }
+ // If monitor is finished, we're done. Cleanup
+ executor.shutdown();
}
}
+++ /dev/null
-/*
- * 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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-
-/**
- * @Since 4.5
- */
-public class Launcher extends Thread {
-
- private final static Logger LOGGER = LoggerFactory.getLogger(Launcher.class);
-
- final String name;
- final DatagramSocket socket;
- java.lang.Process process;
-
-
- public Launcher(String name, DatagramSocket socket) {
- LOGGER.info("Creating Launcher for '{}' with base port: {}", name, socket.getLocalPort());
- this.name = name;
- this.socket = socket;
- }
-
- private void launch() {
-// new Thread(new Runnable() {
-// @Override
-// public void run() {
-// Runner.main(name, socket.getLocalPort() + "");
-// }
-// }).start();
- }
-
- private void shutdown() {
- process.destroy();
- }
-
- private void monitor() {
- long ping = Long.MAX_VALUE;
- while (true) {
- LOGGER.info("My heart is beating");
- DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
- try {
- socket.setSoTimeout(3000);
- socket.receive(packet);
- } catch (Exception e) {
- // Do nothing
- }
- long newPing = System.currentTimeMillis();
- String message = new String(packet.getData(), 0, 0, packet.getLength());
- LOGGER.info("{} last seen since {}ms", message, (newPing - ping));
- if ((newPing - ping) > 3000) {
- // close everything here...
- }
- ping = newPing;
- }
- }
-
- @Override
- public void run() {
- LOGGER.info("launching child VM for " + name);
- launch();
-
- LOGGER.info("Monitoring VM for " + name);
- while (true) {
- monitor();
- }
- }
-}
--- /dev/null
+package org.sonar.process;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MonitorService extends Thread {
+
+ private final static Logger LOGGER = LoggerFactory.getLogger(ProcessWrapper.class);
+
+ final DatagramSocket socket;
+ final Map<String, Thread> processes;
+ final Map<String, Long> processesPing;
+
+ public MonitorService(DatagramSocket socket) {
+ this.socket = socket;
+ processes = new HashMap<String, Thread>();
+ processesPing = new HashMap<String, Long>();
+ }
+
+ public void register(ProcessWrapper process) {
+ this.processes.put(process.getName(), process);
+ this.processesPing.put(process.getName(), System.currentTimeMillis());
+ }
+
+ @Override
+ public void run() {
+ LOGGER.info("Launching Monitoring Thread");
+ long time = System.currentTimeMillis();
+ while (!currentThread().isInterrupted()) {
+ DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
+ try {
+ socket.setSoTimeout(200);
+ socket.receive(packet);
+ time = System.currentTimeMillis();
+ String message = new String(packet.getData());
+ long lastTime = processesPing.get(message);
+ processesPing.put(message, time);
+ LOGGER.info("{} last seen since {}ms", message, (time - lastTime));
+ } catch (Exception e) {
+ // Do nothing
+ }
+ if (!checkAllProcessPing(time)) {
+ break;
+ }
+ }
+ LOGGER.info("Some app has not been pinging");
+ for (Thread process : processes.values()) {
+ if (!process.isInterrupted()) {
+ process.interrupt();
+ }
+ }
+ }
+
+
+ private boolean checkAllProcessPing(long now) {
+
+ //check that all thread wrapper are running
+ for (Thread thread : processes.values()) {
+ if (thread.isInterrupted() || !thread.isAlive()) {
+ return false;
+ }
+ }
+
+ //check that all heartbeats are OK
+ for (Long ping : processesPing.values()) {
+ if ((now - ping) > 3000) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public Integer getMonitoringPort() {
+ return socket.getPort();
+ }
+}
import java.net.DatagramSocket;
import java.net.InetAddress;
-/**
- * @Since 4.5
- */
public abstract class Process implements Runnable {
public static final String NAME_PROPERTY = "pName";
--- /dev/null
+/*
+ * 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 com.google.common.annotations.VisibleForTesting;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProcessWrapper extends Thread {
+
+ private final static Logger LOGGER = LoggerFactory.getLogger(ProcessWrapper.class);
+
+ final String name;
+
+ @VisibleForTesting
+ ProcessWrapper(String name, Integer port) {
+ LOGGER.info("Creating Launcher for '{}' with base port: {}", name, port);
+ this.name = name;
+ }
+
+ public ProcessWrapper(String className, String[] classPath, String name, Integer port) {
+ LOGGER.info("Creating Launcher for '{}' with base port: {}", name, port);
+ this.name = name;
+ }
+
+ public void run() {
+
+ }
+}
+++ /dev/null
-/*
- * 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;
-
-public class LauncherTest {
-
-}
\ No newline at end of file
--- /dev/null
+package org.sonar.process;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.DatagramSocket;
+
+public class MonitorServiceTest {
+
+
+ private DatagramSocket socket;
+
+ @Before
+ public void setUp() throws Exception {
+ socket = new DatagramSocket(0);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (socket != null && !socket.isClosed()) {
+ socket.close();
+ }
+ }
+
+ @Test
+ public void should_build() {
+ MonitorService monitor = new MonitorService(socket);
+ }
+
+ class LongProcessWrapper extends ProcessWrapper {
+
+ LongProcessWrapper(String name, Integer port) {
+ super(name, port);
+ }
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(10000L);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
\ No newline at end of file