From ee692e22c5e27b463bddc67d2a26159713722a2a Mon Sep 17 00:00:00 2001 From: Brian Stansberry Date: Mon, 20 Jan 2025 16:30:54 -0600 Subject: [PATCH] [WFCORE-7143] Consolidate HostControllerBootstrap and EmbeddedHostControllerBootstrap --- .../AbstractHostControllerBootstrap.java | 169 ++++++++++++++++++ .../controller/HostControllerBootstrap.java | 95 +--------- .../EmbeddedHostControllerBootstrap.java | 116 +++--------- 3 files changed, 198 insertions(+), 182 deletions(-) create mode 100644 host-controller/src/main/java/org/jboss/as/host/controller/AbstractHostControllerBootstrap.java diff --git a/host-controller/src/main/java/org/jboss/as/host/controller/AbstractHostControllerBootstrap.java b/host-controller/src/main/java/org/jboss/as/host/controller/AbstractHostControllerBootstrap.java new file mode 100644 index 00000000000..3e8bb086d46 --- /dev/null +++ b/host-controller/src/main/java/org/jboss/as/host/controller/AbstractHostControllerBootstrap.java @@ -0,0 +1,169 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.jboss.as.host.controller; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; + +import org.jboss.as.controller.ControlledProcessState; +import org.jboss.as.controller.ControlledProcessStateService; +import org.jboss.as.controller.ProcessStateNotifier; +import org.jboss.as.server.FutureServiceContainer; +import org.jboss.as.server.jmx.RunningStateJmx; +import org.jboss.msc.service.ServiceActivator; +import org.jboss.msc.service.ServiceContainer; +import org.jboss.msc.service.ServiceTarget; + +/** + * Base class for bootstrapping embedded and non-embedded Host Controllers. + * + * @author Emanuel Muckenhuber + * @author Darran Lofthouse + * @author Brian Stansberry (c) 2011 Red Hat Inc. + * @author Ken Wills (c) 2015 Red Hat Inc. + */ +public abstract class AbstractHostControllerBootstrap { + + private final ShutdownHook shutdownHook; + private final ServiceContainer serviceContainer; + private final HostControllerEnvironment environment; + private final String authCode; + + protected AbstractHostControllerBootstrap(final HostControllerEnvironment environment, final String authCode, + final ShutdownHook shutdownHook) { + this.environment = environment; + this.authCode = authCode; + this.shutdownHook = shutdownHook; + this.serviceContainer = shutdownHook.register(); + } + + /** + * Bootstrap the host controller. + * + * @param embedded {@code true} if the host controller is embedded in another process + * @param extraServices any extra services to launch as part of bootstrap + * @return future that will provide the MSC {@link ServiceContainer} for the host controller + */ + protected final Future bootstrap(boolean embedded, ServiceActivator... extraServices) { + try { + final HostRunningModeControl runningModeControl = environment.getRunningModeControl(); + final ControlledProcessState processState = new ControlledProcessState(true, embedded); + shutdownHook.setControlledProcessState(processState); + ServiceTarget target = serviceContainer.subTarget(); + + final ProcessStateNotifier processStateNotifier = ControlledProcessStateService.addService(target, processState); + RunningStateJmx.registerMBean(processStateNotifier, null, runningModeControl, false); + + final FutureServiceContainer futureServiceContainer = new FutureServiceContainer(); + final HostControllerService hcs = new HostControllerService(environment, runningModeControl, authCode, + processState, futureServiceContainer, extraServices); + target.addService(HostControllerService.HC_SERVICE_NAME, hcs).install(); + return futureServiceContainer; + } catch (RuntimeException | Error e) { + shutdownHook.shutdown(); + throw e; + } + } + + /** + * {@link Runtime#addShutdownHook JVM shutdown hook} thread that cleans up the + * Host Controller services. + */ + public static final class ShutdownHook extends Thread { + + private final Runnable processExitingCallback; + private boolean down; + private ControlledProcessState processState; + private ServiceContainer container; + + /** + * Creates a new {@code ShutdownHook} thread. + */ + public ShutdownHook() { + this(null); + } + + /** + * Creates a new {@code ShutdownHook} thread. + * + * @param processExitingCallback runnable to invoke after the {@code ControlledProcessState} has been + * {@link ControlledProcessState#setStopping() set as stopping} but before + * the MSC {@link ServiceContainer} has been {@link ServiceContainer#shutdown() shut down}. + * May be {@code null}. + */ + public ShutdownHook(Runnable processExitingCallback) { + this.processExitingCallback = processExitingCallback; + } + + private ServiceContainer register() { + + Runtime.getRuntime().addShutdownHook(this); + synchronized (this) { + if (!down) { + container = ServiceContainer.Factory.create("host-controller", false); + return container; + } else { + throw new IllegalStateException(); + } + } + } + + private synchronized void setControlledProcessState(final ControlledProcessState ps) { + this.processState = ps; + } + + /** + * Calls {@link #shutdown()}. + */ + @Override + public void run() { + shutdown(); + } + + /** + * Notifies the {@code ControlledProcessState} for the Host Controller that + * {@link ControlledProcessState#setStopping() it is stopping}, invokes any {@link Runnable} + * provided to our {@link ShutdownHook#ShutdownHook(Runnable) constructor}, and + * {@link ServiceContainer#shutdown() shuts down} the Host Controller's {@link ServiceContainer}. + */ + public void shutdown() { + final ServiceContainer sc; + final ControlledProcessState ps; + synchronized (this) { + down = true; + sc = container; + ps = processState; + } + try { + if (ps != null) { + ps.setStopping(); + } + } finally { + if (sc != null) { + if (processExitingCallback != null) { + processExitingCallback.run(); + } + final CountDownLatch latch = new CountDownLatch(1); + sc.addTerminateListener(new ServiceContainer.TerminateListener() { + @Override + public void handleTermination(Info info) { + latch.countDown(); + } + }); + sc.shutdown(); + // wait for all services to finish. + for (;;) { + try { + latch.await(); + break; + } catch (InterruptedException e) { + } + } + } + } + } + } +} diff --git a/host-controller/src/main/java/org/jboss/as/host/controller/HostControllerBootstrap.java b/host-controller/src/main/java/org/jboss/as/host/controller/HostControllerBootstrap.java index dc23ce74e6e..c4e1e3c69a7 100644 --- a/host-controller/src/main/java/org/jboss/as/host/controller/HostControllerBootstrap.java +++ b/host-controller/src/main/java/org/jboss/as/host/controller/HostControllerBootstrap.java @@ -5,110 +5,31 @@ package org.jboss.as.host.controller; -import java.util.concurrent.CountDownLatch; - -import org.jboss.as.controller.ControlledProcessState; -import org.jboss.as.controller.ProcessStateNotifier; -import org.jboss.as.controller.ControlledProcessStateService; import org.jboss.as.host.controller.logging.HostControllerLogger; -import org.jboss.as.server.jmx.RunningStateJmx; -import org.jboss.msc.service.ServiceContainer; -import org.jboss.msc.service.ServiceTarget; /** - * Bootstrap of the HostController process. + * Bootstrap of a non-embedded HostController process. * * @author Emanuel Muckenhuber * @author Darran Lofthouse * @author Brian Stansberry (c) 2011 Red Hat Inc. */ -public class HostControllerBootstrap { - - private final ShutdownHook shutdownHook; - private final ServiceContainer serviceContainer; - private final HostControllerEnvironment environment; - private final String authCode; +public final class HostControllerBootstrap extends AbstractHostControllerBootstrap { public HostControllerBootstrap(final HostControllerEnvironment environment, final String authCode) { - this.environment = environment; - this.authCode = authCode; - this.shutdownHook = new ShutdownHook(); - this.serviceContainer = shutdownHook.register(); + super(environment, authCode, + new ShutdownHook(HostControllerBootstrap::handleProcessExiting)); } /** * Start the host controller services. - * - * @throws Exception */ - public void bootstrap() throws Exception { - final HostRunningModeControl runningModeControl = environment.getRunningModeControl(); - final ControlledProcessState processState = new ControlledProcessState(true, false); - shutdownHook.setControlledProcessState(processState); - ServiceTarget target = serviceContainer.subTarget(); - ProcessStateNotifier processStateNotifier = ControlledProcessStateService.addService(target, processState); - RunningStateJmx.registerMBean(processStateNotifier, null, runningModeControl, false); - final HostControllerService hcs = new HostControllerService(environment, runningModeControl, authCode, processState); - target.addService(HostControllerService.HC_SERVICE_NAME, hcs).install(); + public void bootstrap() { + bootstrap(false); } - private static class ShutdownHook extends Thread { - private boolean down; - private ControlledProcessState processState; - private ServiceContainer container; - - private ServiceContainer register() { - - Runtime.getRuntime().addShutdownHook(this); - synchronized (this) { - if (!down) { - container = ServiceContainer.Factory.create("host-controller", false); - return container; - } else { - throw new IllegalStateException(); - } - } - } - - private synchronized void setControlledProcessState(final ControlledProcessState ps) { - this.processState = ps; - } - - @Override - public void run() { - final ServiceContainer sc; - final ControlledProcessState ps; - synchronized (this) { - down = true; - sc = container; - ps = processState; - } - try { - if (ps != null) { - ps.setStopping(); - } - } finally { - if (sc != null) { - SystemExiter.logBeforeExit(HostControllerLogger.ROOT_LOGGER::shutdownHookInvoked); - final CountDownLatch latch = new CountDownLatch(1); - sc.addTerminateListener(new ServiceContainer.TerminateListener() { - @Override - public void handleTermination(Info info) { - latch.countDown(); - } - }); - sc.shutdown(); - // wait for all services to finish. - for (;;) { - try { - latch.await(); - break; - } catch (InterruptedException e) { - } - } - } - } - } + private static void handleProcessExiting() { + SystemExiter.logBeforeExit(HostControllerLogger.ROOT_LOGGER::shutdownHookInvoked); } } diff --git a/host-controller/src/main/java/org/jboss/as/host/controller/embedded/EmbeddedHostControllerBootstrap.java b/host-controller/src/main/java/org/jboss/as/host/controller/embedded/EmbeddedHostControllerBootstrap.java index b1038293990..b9d0ad71cd3 100644 --- a/host-controller/src/main/java/org/jboss/as/host/controller/embedded/EmbeddedHostControllerBootstrap.java +++ b/host-controller/src/main/java/org/jboss/as/host/controller/embedded/EmbeddedHostControllerBootstrap.java @@ -6,120 +6,46 @@ package org.jboss.as.host.controller.embedded; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; -import org.jboss.as.controller.ControlledProcessState; -import org.jboss.as.controller.ControlledProcessStateService; +import org.jboss.as.host.controller.AbstractHostControllerBootstrap; import org.jboss.as.host.controller.HostControllerEnvironment; -import org.jboss.as.host.controller.HostControllerService; -import org.jboss.as.host.controller.HostRunningModeControl; -import org.jboss.as.server.FutureServiceContainer; -import org.jboss.as.server.jmx.RunningStateJmx; import org.jboss.msc.service.ServiceActivator; import org.jboss.msc.service.ServiceContainer; -import org.jboss.msc.service.ServiceTarget; /** - * Embedded variant of {@link org.jboss.as.host.controller.HostControllerBootstrap}. TODO WFCORE-7143 see if these can be better unified. + * Embedded variant of {@link org.jboss.as.host.controller.AbstractHostControllerBootstrap}. * * @author Ken Wills (c) 2015 Red Hat Inc. */ -public class EmbeddedHostControllerBootstrap { +public final class EmbeddedHostControllerBootstrap extends AbstractHostControllerBootstrap { private final ShutdownHook shutdownHook; - private final ServiceContainer serviceContainer; - private final HostControllerEnvironment environment; - private final String authCode; - public EmbeddedHostControllerBootstrap(final HostControllerEnvironment environment, final String authCode) { - this.environment = environment; - this.authCode = authCode; - this.shutdownHook = new ShutdownHook(); - this.serviceContainer = shutdownHook.register(); + this(environment, authCode, new ShutdownHook()); } - public Future bootstrap(ServiceActivator... extraServices) throws Exception { - try { - final HostRunningModeControl runningModeControl = environment.getRunningModeControl(); - final ControlledProcessState processState = new ControlledProcessState(true, true); - shutdownHook.setControlledProcessState(processState); - ServiceTarget target = serviceContainer.subTarget(); - - final org.jboss.as.controller.ProcessStateNotifier processStateNotifier = ControlledProcessStateService.addService(target, processState); - RunningStateJmx.registerMBean(processStateNotifier, null, runningModeControl, false); - - final FutureServiceContainer futureServiceContainer = new FutureServiceContainer(); - final HostControllerService hcs = new HostControllerService(environment, runningModeControl, authCode, - processState, futureServiceContainer, extraServices); - target.addService(HostControllerService.HC_SERVICE_NAME, hcs).install(); - return futureServiceContainer; - } catch (RuntimeException | Error e) { - shutdownHook.run(); - throw e; - } + private EmbeddedHostControllerBootstrap(final HostControllerEnvironment environment, final String authCode, + final ShutdownHook shutdownHook) { + super(environment, authCode, shutdownHook); + this.shutdownHook = shutdownHook; } - public void failed() { - shutdownHook.run(); + /** + * Start the host controller services. + * + * @param extraServices any extra services to launch as part of bootstrap + */ + public Future bootstrap(ServiceActivator... extraServices) { + return bootstrap(true, extraServices); } - private static class ShutdownHook extends Thread { - private boolean down; - private ControlledProcessState processState; - private ServiceContainer container; - - private ServiceContainer register() { - - Runtime.getRuntime().addShutdownHook(this); - synchronized (this) { - if (!down) { - container = ServiceContainer.Factory.create("host-controller", false); - return container; - } else { - throw new IllegalStateException(); - } - } - } - - private synchronized void setControlledProcessState(final ControlledProcessState ps) { - this.processState = ps; - } - - @Override - public void run() { - final ServiceContainer sc; - final ControlledProcessState ps; - synchronized (this) { - down = true; - sc = container; - ps = processState; - } - try { - if (ps != null) { - ps.setStopping(); - } - } finally { - if (sc != null) { - final CountDownLatch latch = new CountDownLatch(1); - sc.addTerminateListener(new ServiceContainer.TerminateListener() { - @Override - public void handleTermination(Info info) { - latch.countDown(); - } - }); - sc.shutdown(); - // wait for all services to finish. - for (;;) { - try { - latch.await(); - break; - } catch (InterruptedException e) { - } - } - } - } - } + /** + * Notification that overall embedded Host Controller startup of which a call + * to {@link #bootstrap(ServiceActivator...)} was a part has failed. + */ + public void failed() { + shutdownHook.shutdown(); } }