/** * Launch process and waits until it's down */ public void launch(Monitored mp) { if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) { throw new IllegalStateException("Already started"); } monitored = mp; Logger logger = LoggerFactory.getLogger(getClass()); try { launch(logger); } catch (Exception e) { logger.warn("Fail to start {}", getKey(), e); } finally { stop(); } }
/** * Blocks until stopped in a timely fashion (see {@link org.sonar.process.StopperThread}) */ void stop() { stopAsync(); try { // stopperThread is not null for sure // join() does nothing if thread already finished stopperThread.join(); lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } exit.exit(0); }
@Override public void stopAsync() { if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) { stopperThread = new StopperThread(monitored, commands, Long.parseLong(props.nonNullValue(PROPERTY_TERMINATION_TIMEOUT_MS))); stopperThread.start(); stopWatcher.stopWatching(); } }
private static Lifecycle newLifeCycle(State from, State to) { Lifecycle lifecycle; lifecycle = newLifeCycle(from); assertThat(lifecycle.tryToMoveTo(to)).isTrue(); return lifecycle; }
@Test public void try_to_move_does_not_support_jumping_states() { Lifecycle lifecycle = new Lifecycle(); assertThat(lifecycle.getState()).isEqualTo(INIT); assertThat(lifecycle.tryToMoveTo(STARTED)).isFalse(); assertThat(lifecycle.getState()).isEqualTo(INIT); assertThat(lifecycle.tryToMoveTo(STARTING)).isTrue(); assertThat(lifecycle.getState()).isEqualTo(STARTING); }
@Test public void can_move_to_STARTING_from_RESTARTING() { assertThat(newLifeCycle(RESTARTING).tryToMoveTo(STARTING)).isTrue(); }
private void launch(Logger logger) throws InterruptedException { logger.info("Starting {}", getKey()); Runtime.getRuntime().addShutdownHook(shutdownHook); stopWatcher.start(); monitored.start(); Monitored.Status status = waitForNotDownStatus(); if (status == Monitored.Status.UP || status == Monitored.Status.OPERATIONAL) { // notify monitor that process is ready commands.setUp(); if (lifecycle.tryToMoveTo(Lifecycle.State.STARTED)) { Monitored.Status newStatus = waitForOperational(status); if (newStatus == Monitored.Status.OPERATIONAL && lifecycle.tryToMoveTo(Lifecycle.State.OPERATIONAL)) { commands.setOperational(); } monitored.awaitStop(); } } else { stop(); } }
@Test public void no_state_can_not_move_to_itself() { for (State state : values()) { assertThat(newLifeCycle(state).tryToMoveTo(state)).isFalse(); } }
@Test public void can_move_to_OPERATIONAL_from_STARTED_only() { for (State state : values()) { boolean tryToMoveTo = newLifeCycle(state).tryToMoveTo(OPERATIONAL); if (state == STARTED) { assertThat(tryToMoveTo).describedAs("from state " + state).isTrue(); } else { assertThat(tryToMoveTo).describedAs("from state " + state).isFalse(); } } }
@Test public void can_move_to_STOPPING_from_STARTING_STARTED_OPERATIONAL_only() { for (State state : values()) { boolean tryToMoveTo = newLifeCycle(state).tryToMoveTo(STOPPING); if (state == STARTING || state == STARTED || state == OPERATIONAL) { assertThat(tryToMoveTo).describedAs("from state " + state).isTrue(); } else { assertThat(tryToMoveTo).describedAs("from state " + state).isFalse(); } } }
@Test public void equals_and_hashcode() { Lifecycle init = new Lifecycle(); assertThat(init.equals(init)).isTrue(); assertThat(init.equals(new Lifecycle())).isTrue(); assertThat(init.equals("INIT")).isFalse(); assertThat(init.equals(null)).isFalse(); assertThat(init.hashCode()).isEqualTo(new Lifecycle().hashCode()); // different state Lifecycle stopping = new Lifecycle(); stopping.tryToMoveTo(STARTING); assertThat(stopping).isNotEqualTo(init); }
@Override public void stopAsync() { if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) { stopperThread = new StopperThread(monitored, commands, Long.parseLong(props.nonNullValue(PROPERTY_TERMINATION_TIMEOUT))); stopperThread.start(); stopWatcher.stopWatching(); } }
/** * Launch process and waits until it's down */ public void launch(Monitored mp) { if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) { throw new IllegalStateException("Already started"); } monitored = mp; try { LoggerFactory.getLogger(getClass()).info("Starting " + getKey()); Runtime.getRuntime().addShutdownHook(shutdownHook); stopWatcher.start(); monitored.start(); boolean ready = false; while (!ready) { ready = monitored.isReady(); Thread.sleep(200L); } // notify monitor that process is ready commands.setReady(); if (lifecycle.tryToMoveTo(Lifecycle.State.STARTED)) { monitored.awaitStop(); } } catch (Exception e) { LoggerFactory.getLogger(getClass()).warn("Fail to start " + getKey(), e); } finally { stop(); } }
/** * Blocks until stopped in a timely fashion (see {@link org.sonar.process.StopperThread}) */ void stop() { stopAsync(); try { // stopperThread is not null for sure // join() does nothing if thread already finished stopperThread.join(); lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); } catch (InterruptedException e) { // nothing to do, the process is going to be exited } exit.exit(0); }