Merge branch 'master' of ../infrautils
[odlguice.git] / inject / src / main / java / org / opendaylight / infrautils / inject / AbstractLifecycle.java
diff --git a/inject/src/main/java/org/opendaylight/infrautils/inject/AbstractLifecycle.java b/inject/src/main/java/org/opendaylight/infrautils/inject/AbstractLifecycle.java
new file mode 100644 (file)
index 0000000..117f78e
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016 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.inject;
+
+import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Support class for {@link Lifecycle}. Provides a convenient base
+ * implementation including correct thread safety, exception handling and check
+ * for accidental unnecessary re-start & stop. Subclasses must implement
+ * {@link #start()} & {@link #stop()}.
+ *
+ * @author Michael Vorburger (with guidance re. AtomicReference from Tom Pantelis)
+ */
+public abstract class AbstractLifecycle implements Lifecycle {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractLifecycle.class);
+
+    private enum State {
+        STARTED, STOPPED
+    }
+
+    private final AtomicReference<State> state = new AtomicReference<>(State.STOPPED);
+
+    protected abstract void start() throws Exception;
+
+    protected abstract void stop() throws Exception;
+
+    /**
+     * Please implement {@link #start()} instead of overriding this (here intentionally final) method.
+     */
+    @Override
+    @PostConstruct // NOTE: @PostConstruct is *NOT* inherited from interface, so must be here
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public final void init() throws ModuleSetupRuntimeException {
+        if (state.compareAndSet(State.STOPPED, State.STARTED)) {
+            try {
+                start();
+            } catch (Exception e) {
+                throw new ModuleSetupRuntimeException(e);
+            }
+        } else {
+            LOG.warn("Lifecycled object already started; ignoring start()");
+        }
+    }
+
+    /**
+     * Please implement {@link #stop()} instead of overriding this (here intentionally final) method.
+     */
+    @Override
+    @PreDestroy // NOTE: @PostConstruct is *NOT* inherited from interface, so must be here
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public final void destroy() throws ModuleSetupRuntimeException {
+        if (state.compareAndSet(State.STARTED, State.STOPPED)) {
+            try {
+                stop();
+            } catch (Exception e) {
+                throw new ModuleSetupRuntimeException(e);
+            }
+        } else {
+            LOG.warn("Lifecycled object already stopped; ignoring stop()");
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        return state.get() == State.STARTED;
+    }
+
+    protected void checkIsRunning() {
+        if (!isRunning()) {
+            throw new IllegalStateException("Lifecycled object is already stopped: " + this.toString());
+        }
+    }
+
+}