aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Hahn <jrh3@att.com>2019-03-16 13:47:21 -0400
committerJim Hahn <jrh3@att.com>2019-03-16 16:03:42 -0400
commit1ea998182b78ee8e857aa2974c554ca952f1f68f (patch)
treec5dde345942cbee2d32c1c32304db23466e64fe9
parentd641804925822df207f4e59aed920c013851f93d (diff)
Make ServiceManager implement Startable
Also added a "name" to the manager, for logger purposes. Change-Id: Ide57cdec1fafc36c43b7f7584c0baad6261e8412 Issue-ID: POLICY-1542 Signed-off-by: Jim Hahn <jrh3@att.com>
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java86
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/services/ServiceManagerException.java2
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java62
3 files changed, 114 insertions, 36 deletions
diff --git a/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java b/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java
index 8bf89d56..13cd6de8 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManager.java
@@ -31,10 +31,15 @@ import org.slf4j.LoggerFactory;
* Manages a series of services. The services are started in order, and stopped in reverse
* order.
*/
-public class ServiceManager {
+public class ServiceManager implements Startable {
private static final Logger logger = LoggerFactory.getLogger(ServiceManager.class);
/**
+ * Manager name.
+ */
+ private final String name;
+
+ /**
* Services to be started/stopped.
*/
private final Deque<Service> items = new LinkedList<>();
@@ -45,6 +50,25 @@ public class ServiceManager {
private boolean running;
/**
+ * Constructs the object, with a default name.
+ */
+ public ServiceManager() {
+ this("service manager");
+ }
+
+ /**
+ * Constructs the object.
+ * @param name the manager's name, used for logging purposes
+ */
+ public ServiceManager(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
* Adds a pair of service actions to the manager.
*
* @param stepName name to be logged when the service is started/stopped
@@ -54,7 +78,7 @@ public class ServiceManager {
*/
public synchronized ServiceManager addAction(String stepName, RunnableWithEx starter, RunnableWithEx stopper) {
if (running) {
- throw new IllegalStateException("services are already running; cannot add " + stepName);
+ throw new IllegalStateException(name + " is already running; cannot add " + stepName);
}
items.add(new Service(stepName, starter, stopper));
@@ -71,44 +95,47 @@ public class ServiceManager {
*/
public synchronized ServiceManager addService(String stepName, Startable service) {
if (running) {
- throw new IllegalStateException("services are already running; cannot add " + stepName);
+ throw new IllegalStateException(name + " is already running; cannot add " + stepName);
}
items.add(new Service(stepName, () -> service.start(), () -> service.stop()));
return this;
}
- /**
- * Starts each service, in order. If a service throws an exception, then the
- * previously started services are stopped, in reverse order.
- *
- * @throws ServiceManagerException if a service fails to start
- */
- public synchronized void start() throws ServiceManagerException {
+ @Override
+ public synchronized boolean isAlive() {
+ return running;
+ }
+
+ @Override
+ public synchronized boolean start() {
if (running) {
- throw new IllegalStateException("services are already running");
+ throw new IllegalStateException(name + " is already running");
}
+ logger.info("{} starting", name);
+
// tracks the services that have been started so far
Deque<Service> started = new LinkedList<>();
Exception ex = null;
for (Service item : items) {
try {
- logger.info("starting {}", item.stepName);
+ logger.info("{} starting {}", name, item.stepName);
item.starter.run();
started.add(item);
} catch (Exception e) {
- logger.error("failed to start {}; rewinding steps", item.stepName);
+ logger.error("{} failed to start {}; rewinding steps", name, item.stepName);
ex = e;
break;
}
}
if (ex == null) {
+ logger.info("{} started", name);
running = true;
- return;
+ return true;
}
// one of the services failed to start - rewind those we've previously started
@@ -116,26 +143,27 @@ public class ServiceManager {
rewind(started);
} catch (ServiceManagerException e) {
- logger.error("rewind failed", e);
+ logger.error("{} rewind failed", name, e);
}
throw new ServiceManagerException(ex);
}
- /**
- * Stops the services, in reverse order from which they were started. Stops all of the
- * services, even if one of the "stop" functions throws an exception. Assumes that
- * {@link #start()} has completed successfully.
- *
- * @throws ServiceManagerException if a service fails to stop
- */
- public synchronized void stop() throws ServiceManagerException {
+ @Override
+ public synchronized boolean stop() {
if (!running) {
- throw new IllegalStateException("services are not running");
+ throw new IllegalStateException(name + " is not running");
}
running = false;
rewind(items);
+
+ return true;
+ }
+
+ @Override
+ public void shutdown() {
+ stop();
}
/**
@@ -148,21 +176,25 @@ public class ServiceManager {
private void rewind(Deque<Service> running) throws ServiceManagerException {
Exception ex = null;
+ logger.info("{} stopping", name);
+
// stop everything, in reverse order
Iterator<Service> it = running.descendingIterator();
while (it.hasNext()) {
Service item = it.next();
try {
- logger.info("stopping {}", item.stepName);
+ logger.info("{} stopping {}", name, item.stepName);
item.stopper.run();
} catch (Exception e) {
- logger.error("failed to stop {}", item.stepName);
+ logger.error("{} failed to stop {}", name, item.stepName);
ex = e;
// do NOT break or re-throw, as we must stop ALL remaining items
}
}
+ logger.info("{} stopped", name);
+
if (ex != null) {
throw new ServiceManagerException(ex);
}
@@ -185,6 +217,6 @@ public class ServiceManager {
@FunctionalInterface
public static interface RunnableWithEx {
- public void run() throws Exception;
+ void run() throws Exception;
}
}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManagerException.java b/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManagerException.java
index 3daa441a..ac37b6b4 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManagerException.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/services/ServiceManagerException.java
@@ -23,7 +23,7 @@ package org.onap.policy.common.utils.services;
/**
* Exceptions thrown by the ServiceManager.
*/
-public class ServiceManagerException extends Exception {
+public class ServiceManagerException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ServiceManagerException() {
diff --git a/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java b/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java
index 49c0599b..b7774a5e 100644
--- a/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java
+++ b/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java
@@ -23,6 +23,8 @@ package org.onap.policy.common.utils.services;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -36,7 +38,8 @@ import org.onap.policy.common.capabilities.Startable;
import org.onap.policy.common.utils.services.ServiceManager.RunnableWithEx;
public class ServiceManagerTest {
- private static final String ALREADY_RUNNING = "services are already running";
+ private static final String MY_NAME = "my-name";
+ private static final String ALREADY_RUNNING = MY_NAME + " is already running";
private static final String EXPECTED_EXCEPTION = "expected exception";
private ServiceManager svcmgr;
@@ -46,7 +49,17 @@ public class ServiceManagerTest {
*/
@Before
public void setUp() {
- svcmgr = new ServiceManager();
+ svcmgr = new ServiceManager(MY_NAME);
+ }
+
+ @Test
+ public void testServiceName() {
+ assertEquals("service manager", new ServiceManager().getName());
+ }
+
+ @Test
+ public void testGetName() {
+ assertEquals(MY_NAME, svcmgr.getName());
}
@Test
@@ -106,16 +119,20 @@ public class ServiceManagerTest {
Startable start1 = mock(Startable.class);
svcmgr.addService("test start", start1);
- svcmgr.start();
+ assertTrue(svcmgr.start());
+
+ assertTrue(svcmgr.isAlive());
verify(start1).start();
verify(start1, never()).stop();
// cannot re-start
- assertThatIllegalStateException().isThrownBy(() -> svcmgr.start())
- .withMessage(ALREADY_RUNNING);
+ assertThatIllegalStateException().isThrownBy(() -> svcmgr.start()).withMessage(ALREADY_RUNNING);
// verify that it didn't try to start the service again
verify(start1).start();
+
+ // still running
+ assertTrue(svcmgr.isAlive());
}
@Test
@@ -140,6 +157,8 @@ public class ServiceManagerTest {
assertThatThrownBy(() -> svcmgr.start()).isInstanceOf(ServiceManagerException.class).hasCause(exception);
+ assertFalse(svcmgr.isAlive());
+
verify(start1).start();
verify(start2).start();
verify(start3).start();
@@ -177,6 +196,8 @@ public class ServiceManagerTest {
svcmgr.addService("fifth test start rewind", start5);
assertThatThrownBy(() -> svcmgr.start()).isInstanceOf(ServiceManagerException.class).hasCause(exception);
+
+ assertFalse(svcmgr.isAlive());
}
@Test
@@ -185,8 +206,7 @@ public class ServiceManagerTest {
svcmgr.addService("first stop", start1);
// cannot stop until started
- assertThatIllegalStateException().isThrownBy(() -> svcmgr.stop())
- .withMessage("services are not running");
+ assertThatIllegalStateException().isThrownBy(() -> svcmgr.stop()).withMessage(MY_NAME + " is not running");
// verify that it didn't try to stop the service
verify(start1, never()).stop();
@@ -194,7 +214,9 @@ public class ServiceManagerTest {
// start it
svcmgr.start();
- svcmgr.stop();
+ assertTrue(svcmgr.stop());
+
+ assertFalse(svcmgr.isAlive());
verify(start1).stop();
}
@@ -218,6 +240,28 @@ public class ServiceManagerTest {
verify(stop1).run();
verify(start2).start();
verify(start2).stop();
+
+ assertFalse(svcmgr.isAlive());
+ }
+
+ @Test
+ public void testShutdown() throws Exception {
+ Startable start1 = mock(Startable.class);
+ svcmgr.addService("first stop", start1);
+
+ // cannot stop until started
+ assertThatIllegalStateException().isThrownBy(() -> svcmgr.shutdown()).withMessage(MY_NAME + " is not running");
+
+ // verify that it didn't try to stop the service
+ verify(start1, never()).stop();
+
+ // start it
+ svcmgr.start();
+
+ svcmgr.shutdown();
+
+ assertFalse(svcmgr.isAlive());
+ verify(start1).stop();
}
@Test
@@ -242,6 +286,8 @@ public class ServiceManagerTest {
assertThatThrownBy(() -> svcmgr.stop()).isInstanceOf(ServiceManagerException.class).hasCause(exception);
+ assertFalse(svcmgr.isAlive());
+
// all of them should have been stopped, in reverse order
assertEquals(Arrays.asList("rewind5", "rewind4", "rewind3", "rewind2", "rewind1").toString(), lst.toString());
}