org.opendaylight.infrautils.ready.spi.SimpleSystemReadyMonitor Maven / Gradle / Ivy
/*
* Copyright (c) 2018 Red Hat, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.infrautils.ready.spi;
import static org.opendaylight.infrautils.ready.SystemState.ACTIVE;
import static org.opendaylight.infrautils.ready.SystemState.BOOTING;
import static org.opendaylight.infrautils.ready.SystemState.FAILURE;
import com.google.common.base.Throwables;
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import org.opendaylight.infrautils.ready.SystemReadyListener;
import org.opendaylight.infrautils.ready.SystemReadyMonitor;
import org.opendaylight.infrautils.ready.SystemState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link SystemReadyMonitor} implementation for a "simple" (standalone, Java SE) environment.
* Also used as the base class for the Karaf/OSGi specific implementation.
*
* @author Michael Vorburger.ch, based on code from myself, Tom (concurrency) & Faseela in KarafSystemReadyImpl
*/
public class SimpleSystemReadyMonitor implements SystemReadyMonitor {
private static final Logger LOG = LoggerFactory.getLogger(SimpleSystemReadyMonitor.class);
private final Queue listeners = new ConcurrentLinkedQueue<>();
private final AtomicReference currentSystemState = new AtomicReference<>(BOOTING);
private final AtomicReference currentSystemFailureCause = new AtomicReference<>();
@Override
@SuppressWarnings("checkstyle:IllegalCatch")
public void registerListener(SystemReadyListener listener) {
SystemState state;
synchronized (listeners) {
state = currentSystemState.get();
if (state == BOOTING) {
listeners.add(listener);
}
}
if (state == ACTIVE) {
try {
listener.onSystemBootReady();
} catch (Exception e) {
LOG.error("SystemReadyListener.onSystemBootReady() threw Exception; "
+ "but state was already ACTIVE, going back to FAILURE now", e);
currentSystemState.set(FAILURE);
currentSystemFailureCause.set(e);
// Do not re-throw.
}
}
}
@Override
public SystemState getSystemState() {
return currentSystemState.get();
}
@Override
public String getFailureCause() {
return Optional.ofNullable(currentSystemFailureCause.get())
.map(throwable -> Throwables.getStackTraceAsString(throwable)).orElse("");
}
@SuppressWarnings("checkstyle:IllegalCatch") // below
public void ready() {
SystemReadyListener[] toNotify;
synchronized (listeners) {
toNotify = listeners.toArray(new SystemReadyListener[listeners.size()]);
currentSystemState.set(ACTIVE);
}
LOG.info("System ready; AKA: Aye captain, all warp coils are now operating at peak efficiency! [M.]");
if (toNotify.length > 0) {
LOG.info("Now notifying all its registered SystemReadyListeners...");
}
try {
for (SystemReadyListener element : toNotify) {
element.onSystemBootReady();
}
} catch (Exception e) { // this, intentionally, also catches any RuntimeException
LOG.error("Boot failed; a SystemReadyListener.onSystemBootReady() threw an Exception; "
+ "other registered SystemReadyListeners were not called; SystemState FAILURE", e);
setSystemState(FAILURE);
setSystemFailureCause(e);
// intentionally *NOT* re-throwing
}
}
protected void setSystemState(SystemState state) {
currentSystemState.set(state);
}
protected void setSystemFailureCause(Throwable cause) {
currentSystemFailureCause.set(cause);
}
}