diff --git a/README.adoc b/README.adoc index f17420f..18e0c65 100644 --- a/README.adoc +++ b/README.adoc @@ -83,24 +83,28 @@ try (final ModelControllerClient client = ModelControllerClient.Factory.create(I } ---- -== Server Helper +== Server Utilities -You can also use the `org.wildfly.plugin.core.ServerHelper` to interact with a running server. +You can also use the `org.wildfly.plugin.tools.server.DomainManager`, `org.wildfly.plugin.tools.server.ServerManager` +and `org.wildfly.plugin.tools.server.StandaloneManager` utilities to interact with a running server. [source,java] ---- final Path wildflyHome = Paths.get(System.getProperty("user.home"), "servers", "wildfly-10.0.0.Final"); final Process process = Launcher.of(StandaloneCommandBuilder.of(wildflyHome)).launch(); try (final ModelControllerClient client = ModelControllerClient.Factory.create(InetAddress.getLocalHost(), 9990)) { + final StandaloneManager serverManager = ServerManager.builder().client(client).process(process).standalone(); // Wait at the maximum 30 seconds for the server to start - ServerHelper.waitForStandalone(client, 30); + if (!serverManager.waitFor(30, TimeUnit.SECONDS)) { + throw new RuntimeException("Server did not start within 30 seconds."); + } final Path deploymentPath = Paths.get(System.getProperty("user.home"), "projects", "myapp", "target", "myapp.war"); - final DeploymentManager deploymentManager = DeploymentManager.Factory.create(client); + final DeploymentManager deploymentManager = serverManager.deploymentManager(); final Deployment deployment = Deployment.of(deploymentPath); deploymentManager.forceDeploy(deployment).assertSuccess(); // Shutdown the standalone server - ServerHelper.shutdownStandalone(client); + serverManager.shutdown(); } finally { process.destroy(); } diff --git a/src/main/java/org/wildfly/plugin/tools/DefaultDeploymentManager.java b/src/main/java/org/wildfly/plugin/tools/DefaultDeploymentManager.java index edff651..cd16eb6 100644 --- a/src/main/java/org/wildfly/plugin/tools/DefaultDeploymentManager.java +++ b/src/main/java/org/wildfly/plugin/tools/DefaultDeploymentManager.java @@ -9,7 +9,6 @@ import static org.jboss.as.controller.client.helpers.ClientConstants.DEPLOYMENT; import static org.jboss.as.controller.client.helpers.ClientConstants.READ_CHILDREN_NAMES_OPERATION; import static org.jboss.as.controller.client.helpers.ClientConstants.SERVER_GROUP; -import static org.wildfly.plugin.tools.DeploymentOperations.createAddress; import java.io.IOException; import java.io.UncheckedIOException; @@ -231,7 +230,7 @@ public Set getDeployments() throws IOException { // Get all the deployments in the deployment repository builder.addStep(readDeployments); - final ModelNode address = createAddress(SERVER_GROUP, "*", DEPLOYMENT, "*"); + final ModelNode address = Operations.createAddress(SERVER_GROUP, "*", DEPLOYMENT, "*"); // Get all the deployments that are deployed to server groups builder.addStep(Operations.createReadResourceOperation(address)); @@ -324,7 +323,7 @@ public boolean hasDeployment(final String name) { @Override public boolean hasDeployment(final String name, final String serverGroup) { - final ModelNode address = DeploymentOperations.createAddress(SERVER_GROUP, + final ModelNode address = Operations.createAddress(SERVER_GROUP, Assertions.requiresNotNullOrNotEmptyParameter("serverGroup", serverGroup)); return hasDeployment(address, Assertions.requiresNotNullOrNotEmptyParameter("name", name)); } @@ -332,12 +331,12 @@ public boolean hasDeployment(final String name, final String serverGroup) { @Override public boolean isEnabled(final String name) { return isEnabled( - DeploymentOperations.createAddress(DEPLOYMENT, Assertions.requiresNotNullOrNotEmptyParameter("name", name))); + Operations.createAddress(DEPLOYMENT, Assertions.requiresNotNullOrNotEmptyParameter("name", name))); } @Override public boolean isEnabled(final String name, final String serverGroup) { - return isEnabled(DeploymentOperations.createAddress( + return isEnabled(Operations.createAddress( SERVER_GROUP, Assertions.requiresNotNullOrNotEmptyParameter("serverGroup", serverGroup), DEPLOYMENT, @@ -389,7 +388,7 @@ private DeploymentResult execute(final Operation op) throws IOException { private DeploymentDescription getServerGroupDeployment(final String name) throws IOException { final Set serverGroups = new LinkedHashSet<>(); - final ModelNode address = createAddress(SERVER_GROUP, "*", DEPLOYMENT, name); + final ModelNode address = Operations.createAddress(SERVER_GROUP, "*", DEPLOYMENT, name); final ModelNode result = client.execute(Operations.createReadResourceOperation(address)); if (Operations.isSuccessfulOutcome(result)) { @@ -520,7 +519,7 @@ private ContainerDescription get() { synchronized (this) { if (containerDescription == null) { try { - containerDescription = ServerHelper.getContainerDescription(client); + containerDescription = ContainerDescription.lookup(client); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/src/main/java/org/wildfly/plugin/tools/DeploymentOperations.java b/src/main/java/org/wildfly/plugin/tools/DeploymentOperations.java index 271d918..eeaaa99 100644 --- a/src/main/java/org/wildfly/plugin/tools/DeploymentOperations.java +++ b/src/main/java/org/wildfly/plugin/tools/DeploymentOperations.java @@ -17,15 +17,13 @@ import static org.jboss.as.controller.client.helpers.Operations.createOperation; import static org.jboss.as.controller.client.helpers.Operations.createRemoveOperation; -import java.util.Arrays; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; import org.jboss.as.controller.client.Operation; +import org.jboss.as.controller.client.helpers.Operations; import org.jboss.as.controller.client.helpers.Operations.CompositeOperationBuilder; import org.jboss.dmr.ModelNode; -import org.jboss.dmr.ModelType; import org.wildfly.common.Assert; import org.wildfly.plugin.tools.util.Assertions; @@ -43,7 +41,6 @@ * * @author James R. Perkins */ -@SuppressWarnings({ "unused", "StaticMethodOnlyUsedInOneClass", "WeakerAccess" }) public class DeploymentOperations { static final String ENABLED = "enabled"; static final ModelNode EMPTY_ADDRESS = new ModelNode().setEmptyList(); @@ -52,45 +49,6 @@ public class DeploymentOperations { EMPTY_ADDRESS.protect(); } - /** - * Creates an {@linkplain ModelNode address} that can be used as the address for an operation. The address is - * simply a {@link ModelNode} of type {@link ModelType#LIST}. - *

- * The string is split into key/value pairs. If the final key does not have a value an {@code *} is used to - * indicate a wildcard for the address. - *

- * - * @param pairs the key/value pairs to use - * - * @return an address for the key/value pairs - */ - static ModelNode createAddress(final String... pairs) { - return createAddress(Arrays.asList(pairs)); - } - - /** - * Creates an {@linkplain ModelNode address} that can be used as the address for an operation. The address is - * simply a {@link ModelNode} of type {@link ModelType#LIST}. - *

- * The string is split into key/value pairs. If the final key does not have a value an {@code *} is used to - * indicate a wildcard for the address. - *

- * - * @param pairs the key/value pairs to use - * - * @return an address for the key/value pairs - */ - static ModelNode createAddress(final Iterable pairs) { - final ModelNode address = new ModelNode(); - final Iterator iterator = pairs.iterator(); - while (iterator.hasNext()) { - final String key = iterator.next(); - final String value = (iterator.hasNext() ? iterator.next() : "*"); - address.add(key, value); - } - return address; - } - /** * Creates an operation to add deployment content to a running server. If the deployment is set to be * {@linkplain Deployment#isEnabled() enabled} the content will also be deployed. @@ -288,7 +246,7 @@ public static Operation createUndeployOperation(final Set u */ static void addDeploymentOperationStep(final CompositeOperationBuilder builder, final Deployment deployment) { final String name = deployment.getName(); - final ModelNode address = createAddress(DEPLOYMENT, name); + final ModelNode address = Operations.createAddress(DEPLOYMENT, name); final String runtimeName = deployment.getRuntimeName(); final ModelNode addOperation = createAddOperation(address); if (runtimeName != null) { @@ -302,7 +260,7 @@ static void addDeploymentOperationStep(final CompositeOperationBuilder builder, // If the server groups are empty this is a standalone deployment if (!serverGroups.isEmpty()) { for (String serverGroup : serverGroups) { - final ModelNode sgAddress = createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); + final ModelNode sgAddress = Operations.createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); final ModelNode op = createAddOperation(sgAddress); op.get(ENABLED).set(deployment.isEnabled()); @@ -326,11 +284,11 @@ static void addDeployOperationStep(final CompositeOperationBuilder builder, fina final Set serverGroups = deployment.getServerGroups(); // If the server groups are empty this is a standalone deployment if (serverGroups.isEmpty()) { - final ModelNode address = createAddress(DEPLOYMENT, name); + final ModelNode address = Operations.createAddress(DEPLOYMENT, name); builder.addStep(createOperation(DEPLOYMENT_DEPLOY_OPERATION, address)); } else { for (String serverGroup : serverGroups) { - final ModelNode address = createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); + final ModelNode address = Operations.createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); builder.addStep(createOperation(DEPLOYMENT_DEPLOY_OPERATION, address)); } } @@ -360,7 +318,7 @@ static void addReplaceOperationSteps(final CompositeOperationBuilder builder, fi if (!serverGroups.isEmpty()) { serverGroups.removeAll(currentDeployment.getServerGroups()); for (String serverGroup : serverGroups) { - final ModelNode sgAddress = createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); + final ModelNode sgAddress = Operations.createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); final ModelNode addOp = createAddOperation(sgAddress); // Explicitly set to false here as the full-replace-deployment should take care of enabling this addOp.get(ENABLED).set(false); @@ -411,11 +369,12 @@ private static void addRedeployOperationStep(final CompositeOperationBuilder bui final String deploymentName = deployment.getName(); final Set serverGroups = deployment.getServerGroups(); if (serverGroups.isEmpty()) { - builder.addStep(createOperation(DEPLOYMENT_REDEPLOY_OPERATION, createAddress(DEPLOYMENT, deploymentName))); + builder.addStep( + createOperation(DEPLOYMENT_REDEPLOY_OPERATION, Operations.createAddress(DEPLOYMENT, deploymentName))); } else { for (String serverGroup : serverGroups) { builder.addStep(createOperation(DEPLOYMENT_REDEPLOY_OPERATION, - createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, deploymentName))); + Operations.createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, deploymentName))); } } } @@ -425,21 +384,21 @@ private static void addUndeployOperationStep(final CompositeOperationBuilder bui final String name = undeployDescription.getName(); final Set serverGroups = undeployDescription.getServerGroups(); if (serverGroups.isEmpty()) { - final ModelNode address = createAddress(DEPLOYMENT, name); + final ModelNode address = Operations.createAddress(DEPLOYMENT, name); builder.addStep(createOperation(DEPLOYMENT_UNDEPLOY_OPERATION, address)); if (undeployDescription.isRemoveContent()) { builder.addStep(createRemoveOperation(address)); } } else { for (String serverGroup : serverGroups) { - final ModelNode address = createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); + final ModelNode address = Operations.createAddress(SERVER_GROUP, serverGroup, DEPLOYMENT, name); builder.addStep(createOperation(DEPLOYMENT_UNDEPLOY_OPERATION, address)); if (undeployDescription.isRemoveContent()) { builder.addStep(createRemoveOperation(address)); } } if (undeployDescription.isRemoveContent()) { - builder.addStep(createRemoveOperation(createAddress(DEPLOYMENT, name))); + builder.addStep(createRemoveOperation(Operations.createAddress(DEPLOYMENT, name))); } } } diff --git a/src/main/java/org/wildfly/plugin/tools/OperationExecutionException.java b/src/main/java/org/wildfly/plugin/tools/OperationExecutionException.java index a06034e..08fa791 100644 --- a/src/main/java/org/wildfly/plugin/tools/OperationExecutionException.java +++ b/src/main/java/org/wildfly/plugin/tools/OperationExecutionException.java @@ -62,6 +62,17 @@ public OperationExecutionException(final String message, final ModelNode operati this.result.protect(); } + /** + * Creates a new exception with the failure message from the result. + * + * @param message the message to prepend to the failure message + * @param cause the cause of the error + */ + public OperationExecutionException(final String message, final Throwable cause) { + super(message, cause); + result = new ModelNode(message + ": " + cause.getMessage()); + } + /** * Returns the result from the operation executed. * diff --git a/src/main/java/org/wildfly/plugin/tools/ServerHelper.java b/src/main/java/org/wildfly/plugin/tools/ServerHelper.java index f3a1289..98956a9 100644 --- a/src/main/java/org/wildfly/plugin/tools/ServerHelper.java +++ b/src/main/java/org/wildfly/plugin/tools/ServerHelper.java @@ -5,41 +5,34 @@ package org.wildfly.plugin.tools; -import static org.jboss.as.controller.client.helpers.ClientConstants.CONTROLLER_PROCESS_STATE_STARTING; -import static org.jboss.as.controller.client.helpers.ClientConstants.CONTROLLER_PROCESS_STATE_STOPPING; - import java.io.IOException; -import java.nio.file.Files; +import java.io.UncheckedIOException; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.jboss.as.controller.client.ModelControllerClient; -import org.jboss.as.controller.client.helpers.Operations; -import org.jboss.as.controller.client.helpers.Operations.CompositeOperationBuilder; -import org.jboss.as.controller.client.helpers.domain.DomainClient; -import org.jboss.as.controller.client.helpers.domain.ServerIdentity; -import org.jboss.as.controller.client.helpers.domain.ServerStatus; import org.jboss.dmr.ModelNode; -import org.jboss.logging.Logger; import org.wildfly.common.Assert; +import org.wildfly.plugin.tools.server.DomainManager; +import org.wildfly.plugin.tools.server.ServerManager; +import org.wildfly.plugin.tools.server.StandaloneManager; + +; /** * @author James R. Perkins + * + * @deprecated Use the {@link ServerManager}, {@link StandaloneManager} and {@link DomainManager} utilities as + * replacements. + * + * @see ServerManager + * @see StandaloneManager + * @see DomainManager */ -@SuppressWarnings({ "StaticMethodOnlyUsedInOneClass", "WeakerAccess", "unused", "MagicNumber" }) +@SuppressWarnings("unused") +@Deprecated(forRemoval = true, since = "1.0.1.Final") public class ServerHelper { - private static final ModelNode EMPTY_ADDRESS = new ModelNode().setEmptyList(); - private static final Logger LOGGER = Logger.getLogger(ServerHelper.class); - - static { - EMPTY_ADDRESS.protect(); - } /** * Checks whether or not the directory is a valid home directory for a server. @@ -52,10 +45,7 @@ public class ServerHelper { * @return {@code true} if the path is valid otherwise {@code false} */ public static boolean isValidHomeDirectory(final Path path) { - return path != null - && Files.exists(path) - && Files.isDirectory(path) - && Files.exists(path.resolve("jboss-modules.jar")); + return ServerManager.isValidHomeDirectory(path); } /** @@ -69,7 +59,7 @@ public static boolean isValidHomeDirectory(final Path path) { * @return {@code true} if the path is valid otherwise {@code false} */ public static boolean isValidHomeDirectory(final String path) { - return path != null && isValidHomeDirectory(Paths.get(path)); + return ServerManager.isValidHomeDirectory(path); } /** @@ -81,6 +71,7 @@ public static boolean isValidHomeDirectory(final String path) { * * @throws IOException if an error occurs communicating with the server * @throws OperationExecutionException if the operation used to query the container fails + * @see ContainerDescription#lookup(ModelControllerClient) */ public static ContainerDescription getContainerDescription(final ModelControllerClient client) throws IOException, OperationExecutionException { @@ -93,19 +84,10 @@ public static ContainerDescription getContainerDescription(final ModelController * @param client the client used to execute the operation */ public static void reloadIfRequired(final ModelControllerClient client, final long timeout) { - final String launchType = launchType(client); - if ("STANDALONE".equalsIgnoreCase(launchType)) { - final String runningState = serverState(client); - if ("reload-required".equalsIgnoreCase(runningState)) { - executeReload(client, Operations.createOperation("reload")); - try { - waitForStandalone(client, timeout); - } catch (InterruptedException | TimeoutException e) { - throw new RuntimeException("Failed to reload the serve.", e); - } - } - } else { - LOGGER.warnf("Server type %s is not supported for a reload.", launchType); + try { + ServerManager.builder().client(client).standalone().reloadIfRequired(timeout, TimeUnit.SECONDS); + } catch (IOException e) { + throw new UncheckedIOException(e); } } @@ -116,18 +98,7 @@ public static void reloadIfRequired(final ModelControllerClient client, final lo * @param reloadOp the reload operation to execute */ public static void executeReload(final ModelControllerClient client, final ModelNode reloadOp) { - try { - final ModelNode result = client.execute(reloadOp); - if (!Operations.isSuccessfulOutcome(result)) { - throw new RuntimeException(String.format("Failed to reload the server with %s: %s", reloadOp, - Operations.getFailureDescription(result))); - } - } catch (IOException e) { - final Throwable cause = e.getCause(); - if (!(cause instanceof ExecutionException) && !(cause instanceof CancellationException)) { - throw new RuntimeException(e); - } // else ignore, this might happen if the channel gets closed before we got the response - } + ServerManager.builder().client(client).standalone().executeReload(reloadOp); } /** @@ -137,15 +108,7 @@ public static void executeReload(final ModelControllerClient client, final Model * @return the servers launch-type or "unknown" if it could not be determined */ public static String launchType(final ModelControllerClient client) { - try { - final ModelNode response = client.execute(Operations.createReadAttributeOperation(EMPTY_ADDRESS, "launch-type")); - if (Operations.isSuccessfulOutcome(response)) { - return Operations.readResult(response).asString(); - } - } catch (RuntimeException | IOException e) { - LOGGER.trace("Interrupted determining the launch type", e); - } - return "unknown"; + return ServerManager.launchType(client).orElse("unknown"); } /** @@ -156,18 +119,7 @@ public static String launchType(final ModelControllerClient client) { * standalone server */ public static String serverState(final ModelControllerClient client) { - final String launchType = launchType(client); - if ("STANDALONE".equalsIgnoreCase(launchType)) { - try { - final ModelNode response = client - .execute(Operations.createReadAttributeOperation(EMPTY_ADDRESS, "server-state")); - return Operations.isSuccessfulOutcome(response) ? Operations.readResult(response).asString() : "failed"; - } catch (RuntimeException | IOException e) { - LOGGER.tracef("Interrupted determining the server state", e); - } - return "failed"; - } - return "unknown"; + return ServerManager.builder().client(client).standalone().serverState(); } /** @@ -204,28 +156,7 @@ public static void waitForDomain(final ModelControllerClient client, final long */ public static void waitForDomain(final Process process, final ModelControllerClient client, final long startupTimeout) throws InterruptedException, RuntimeException, TimeoutException { - Assert.checkNotNullParam("client", client); - long timeout = startupTimeout * 1000; - final long sleep = 100; - while (timeout > 0) { - long before = System.currentTimeMillis(); - if (isDomainRunning(client)) { - break; - } - timeout -= (System.currentTimeMillis() - before); - if (process != null && !process.isAlive()) { - throw new RuntimeException( - String.format("The process has unexpectedly exited with code %d", process.exitValue())); - } - TimeUnit.MILLISECONDS.sleep(sleep); - timeout -= sleep; - } - if (timeout <= 0) { - if (process != null) { - process.destroy(); - } - throw new TimeoutException(String.format("The server did not start within %s seconds.", startupTimeout)); - } + ServerManager.builder().process(process).client(client).domain().waitFor(startupTimeout); } /** @@ -237,7 +168,7 @@ public static void waitForDomain(final Process process, final ModelControllerCli * @return {@code true} if the server is in a running state, otherwise {@code false} */ public static boolean isDomainRunning(final ModelControllerClient client) { - return isDomainRunning(client, false); + return ServerManager.builder().client(client).domain().isRunning(); } /** @@ -249,7 +180,7 @@ public static boolean isDomainRunning(final ModelControllerClient client) { * @throws OperationExecutionException if the operation used to shutdown the managed domain failed */ public static void shutdownDomain(final ModelControllerClient client) throws IOException, OperationExecutionException { - shutdownDomain(client, 0); + ServerManager.builder().client(client).domain().shutdown(0L); } /** @@ -264,36 +195,7 @@ public static void shutdownDomain(final ModelControllerClient client) throws IOE */ public static void shutdownDomain(final ModelControllerClient client, final int timeout) throws IOException, OperationExecutionException { - // Note the following two operations used to shutdown a domain don't seem to work well in a composite operation. - // The operation occasionally sees a java.util.concurrent.CancellationException because the operation client - // is likely closed before the AsyncFuture.get() is complete. Using a non-composite operation doesn't seem to - // have this issue. - - // First shutdown the servers - final ModelNode stopServersOp = Operations.createOperation("stop-servers"); - stopServersOp.get("blocking").set(true); - stopServersOp.get("timeout").set(timeout); - ModelNode response = client.execute(stopServersOp); - if (!Operations.isSuccessfulOutcome(response)) { - throw new OperationExecutionException("Failed to stop servers.", stopServersOp, response); - } - - // Now shutdown the host - final ModelNode address = determineHostAddress(client); - final ModelNode shutdownOp = Operations.createOperation("shutdown", address); - response = client.execute(shutdownOp); - if (Operations.isSuccessfulOutcome(response)) { - // Wait until the process has died - while (true) { - if (isDomainRunning(client, true)) { - Thread.onSpinWait(); - } else { - break; - } - } - } else { - throw new OperationExecutionException("Failed to shutdown host.", shutdownOp, response); - } + ServerManager.builder().client(client).domain().shutdown(timeout); } /** @@ -308,12 +210,7 @@ public static void shutdownDomain(final ModelControllerClient client, final int */ public static ModelNode determineHostAddress(final ModelControllerClient client) throws IOException, OperationExecutionException { - final ModelNode op = Operations.createReadAttributeOperation(EMPTY_ADDRESS, "local-host-name"); - ModelNode response = client.execute(op); - if (Operations.isSuccessfulOutcome(response)) { - return DeploymentOperations.createAddress("host", Operations.readResult(response).asString()); - } - throw new OperationExecutionException(op, response); + return ServerManager.builder().client(client).domain().determineHostAddress(); } /** @@ -348,27 +245,7 @@ public static void waitForStandalone(final ModelControllerClient client, final l */ public static void waitForStandalone(final Process process, final ModelControllerClient client, final long startupTimeout) throws InterruptedException, RuntimeException, TimeoutException { - Assert.checkNotNullParam("client", client); - long timeout = startupTimeout * 1000; - final long sleep = 100L; - while (timeout > 0) { - long before = System.currentTimeMillis(); - if (isStandaloneRunning(client)) - break; - timeout -= (System.currentTimeMillis() - before); - if (process != null && !process.isAlive()) { - throw new RuntimeException( - String.format("The process has unexpectedly exited with code %d", process.exitValue())); - } - TimeUnit.MILLISECONDS.sleep(sleep); - timeout -= sleep; - } - if (timeout <= 0) { - if (process != null) { - process.destroy(); - } - throw new TimeoutException(String.format("The server did not start within %s seconds.", startupTimeout)); - } + ServerManager.builder().process(process).client(client).standalone().waitFor(startupTimeout); } /** @@ -379,17 +256,7 @@ public static void waitForStandalone(final Process process, final ModelControlle * @return {@code true} if the server is running, otherwise {@code false} */ public static boolean isStandaloneRunning(final ModelControllerClient client) { - try { - final ModelNode response = client.execute(Operations.createReadAttributeOperation(EMPTY_ADDRESS, "server-state")); - if (Operations.isSuccessfulOutcome(response)) { - final String state = Operations.readResult(response).asString(); - return !CONTROLLER_PROCESS_STATE_STARTING.equals(state) - && !CONTROLLER_PROCESS_STATE_STOPPING.equals(state); - } - } catch (RuntimeException | IOException e) { - LOGGER.trace("Interrupted determining if standalone is running", e); - } - return false; + return ServerManager.builder().client(client).standalone().isRunning(); } /** @@ -413,61 +280,6 @@ public static void shutdownStandalone(final ModelControllerClient client) throws * @throws IOException if an error occurs communicating with the server */ public static void shutdownStandalone(final ModelControllerClient client, final int timeout) throws IOException { - final ModelNode op = Operations.createOperation("shutdown"); - op.get("timeout").set(timeout); - final ModelNode response = client.execute(op); - if (Operations.isSuccessfulOutcome(response)) { - while (true) { - if (isStandaloneRunning(client)) { - Thread.onSpinWait(); - } else { - break; - } - } - } else { - throw new OperationExecutionException(op, response); - } - } - - private static boolean isDomainRunning(final ModelControllerClient client, boolean shutdown) { - final DomainClient domainClient = (client instanceof DomainClient ? (DomainClient) client - : DomainClient.Factory.create(client)); - try { - // Check for admin-only - final ModelNode hostAddress = determineHostAddress(domainClient); - final CompositeOperationBuilder builder = CompositeOperationBuilder.create() - .addStep(Operations.createReadAttributeOperation(hostAddress, "running-mode")) - .addStep(Operations.createReadAttributeOperation(hostAddress, "host-state")); - ModelNode response = domainClient.execute(builder.build()); - if (Operations.isSuccessfulOutcome(response)) { - response = Operations.readResult(response); - if ("ADMIN_ONLY".equals(Operations.readResult(response.get("step-1")).asString())) { - if (Operations.isSuccessfulOutcome(response.get("step-2"))) { - final String state = Operations.readResult(response).asString(); - return !CONTROLLER_PROCESS_STATE_STARTING.equals(state) - && !CONTROLLER_PROCESS_STATE_STOPPING.equals(state); - } - } - } - final Map servers = new HashMap<>(); - final Map statuses = domainClient.getServerStatuses(); - for (ServerIdentity id : statuses.keySet()) { - final ServerStatus status = statuses.get(id); - switch (status) { - case DISABLED: - case STARTED: { - servers.put(id, status); - break; - } - } - } - if (shutdown) { - return statuses.isEmpty(); - } - return statuses.size() == servers.size(); - } catch (Exception e) { - LOGGER.trace("Interrupted determining if domain is running", e); - } - return false; + ServerManager.builder().client(client).standalone().shutdown(timeout); } } diff --git a/src/main/java/org/wildfly/plugin/tools/server/AbstractServerManager.java b/src/main/java/org/wildfly/plugin/tools/server/AbstractServerManager.java new file mode 100644 index 0000000..922a06c --- /dev/null +++ b/src/main/java/org/wildfly/plugin/tools/server/AbstractServerManager.java @@ -0,0 +1,131 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugin.tools.server; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.helpers.Operations; +import org.jboss.dmr.ModelNode; +import org.jboss.logging.Logger; +import org.wildfly.plugin.tools.ContainerDescription; +import org.wildfly.plugin.tools.DeploymentManager; + +/** + * A utility for validating a server installations and executing common operations. + * + * @author James R. Perkins + */ +@SuppressWarnings("unused") +abstract class AbstractServerManager implements ServerManager { + private static final Logger LOGGER = Logger.getLogger(AbstractServerManager.class); + + protected final ProcessHandle process; + private final DeploymentManager deploymentManager; + + protected AbstractServerManager(final ProcessHandle process, final ModelControllerClient client) { + this.process = process; + deploymentManager = DeploymentManager.Factory.create(client); + } + + @Override + public ContainerDescription containerDescription() throws IOException { + return ContainerDescription.lookup(client()); + } + + @Override + public DeploymentManager deploymentManager() { + return deploymentManager; + } + + /** + * Determines the servers "launch-type". + * + * @return the servers launch-type or "unknown" if it could not be determined + */ + @Override + public String launchType() { + return ServerManager.launchType(client()).orElse("unknown"); + } + + @Override + public boolean waitFor(final long startupTimeout, final TimeUnit unit) throws InterruptedException { + long timeout = unit.toMillis(startupTimeout); + final long sleep = 100; + while (timeout > 0) { + long before = System.currentTimeMillis(); + if (isRunning()) { + break; + } + timeout -= (System.currentTimeMillis() - before); + if (process != null && !process.isAlive()) { + throw new RuntimeException( + String.format("The process %d is no longer active.", process.pid())); + } + TimeUnit.MILLISECONDS.sleep(sleep); + timeout -= sleep; + } + if (timeout <= 0) { + if (process != null) { + process.destroy(); + } + return false; + } + return true; + } + + /** + * Takes a snapshot of the current servers configuration and returns the relative file name of the snapshot. + *

+ * This simply executes the {@code take-snapshot} operation with no arguments. + *

+ * + * @return the file name of the snapshot configuration file + * + * @throws IOException if an error occurs executing the operation + */ + @Override + public String takeSnapshot() throws IOException { + final ModelNode op = Operations.createOperation("take-snapshot"); + final ModelNode result = client().execute(op); + if (!Operations.isSuccessfulOutcome(result)) { + throw new RuntimeException( + "The take-snapshot operation did not complete successfully: " + Operations.getFailureDescription(result) + .asString()); + } + final String snapshot = Operations.readResult(result) + .asString(); + return snapshot.contains(File.separator) + ? snapshot.substring(snapshot.lastIndexOf(File.separator) + 1) + : snapshot; + } + + /** + * Reloads the server and returns immediately. + * + * @param reloadOp the reload operation to execute + */ + @Override + public void executeReload(final ModelNode reloadOp) { + try { + @SuppressWarnings("resource") + final ModelNode result = client().execute(reloadOp); + if (!Operations.isSuccessfulOutcome(result)) { + throw new RuntimeException(String.format("Failed to reload the server with %s: %s", reloadOp, + Operations.getFailureDescription(result))); + } + } catch (IOException e) { + final Throwable cause = e.getCause(); + if (!(cause instanceof ExecutionException) && !(cause instanceof CancellationException)) { + throw new RuntimeException(e); + } // else ignore, this might happen if the channel gets closed before we got the response + } + } +} diff --git a/src/main/java/org/wildfly/plugin/tools/server/CommonOperations.java b/src/main/java/org/wildfly/plugin/tools/server/CommonOperations.java new file mode 100644 index 0000000..569ea50 --- /dev/null +++ b/src/main/java/org/wildfly/plugin/tools/server/CommonOperations.java @@ -0,0 +1,118 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugin.tools.server; + +import static org.jboss.as.controller.client.helpers.ClientConstants.CONTROLLER_PROCESS_STATE_STARTING; +import static org.jboss.as.controller.client.helpers.ClientConstants.CONTROLLER_PROCESS_STATE_STOPPING; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.helpers.Operations; +import org.jboss.as.controller.client.helpers.domain.DomainClient; +import org.jboss.as.controller.client.helpers.domain.ServerIdentity; +import org.jboss.as.controller.client.helpers.domain.ServerStatus; +import org.jboss.dmr.ModelNode; +import org.jboss.logging.Logger; +import org.wildfly.plugin.tools.OperationExecutionException; + +/** + * Commonly shared management operations. + * + * @author James R. Perkins + */ +class CommonOperations { + static final ModelNode EMPTY_ADDRESS = new ModelNode().setEmptyList(); + private static final Logger LOGGER = Logger.getLogger(CommonOperations.class); + + static { + EMPTY_ADDRESS.protect(); + } + + /** + * Determines the address for the host being used. + * + * @return the address of the host + * + * @throws IOException if an error occurs communicating with the server + * @throws OperationExecutionException if the operation used to determine the host name fails + */ + static ModelNode determineHostAddress(final ModelControllerClient client) + throws IOException, OperationExecutionException { + final ModelNode op = Operations.createReadAttributeOperation(EMPTY_ADDRESS, "local-host-name"); + ModelNode response = client.execute(op); + if (Operations.isSuccessfulOutcome(response)) { + return Operations.createAddress("host", Operations.readResult(response).asString()); + } + throw new OperationExecutionException(op, response); + } + + /** + * Checks if a standalone server is running. + * + * @param client the client used to check the server state + * + * @return {@code true} if a server is running, otherwise {@code false} + */ + static boolean isStandaloneRunning(final ModelControllerClient client) { + try { + final ModelNode response = client + .execute(Operations.createReadAttributeOperation(new ModelNode().setEmptyList(), "server-state")); + if (Operations.isSuccessfulOutcome(response)) { + final String state = Operations.readResult(response).asString(); + return !CONTROLLER_PROCESS_STATE_STARTING.equals(state) + && !CONTROLLER_PROCESS_STATE_STOPPING.equals(state); + } + } catch (RuntimeException | IOException e) { + Logger.getLogger(ServerManager.class).trace("Interrupted determining if server is running", e); + } + return false; + } + + static boolean isDomainRunning(final ModelControllerClient client, final boolean shutdown) { + final DomainClient domainClient = (client instanceof DomainClient) ? (DomainClient) client + : DomainClient.Factory.create(client); + try { + // Check for admin-only + final ModelNode hostAddress = determineHostAddress(domainClient); + final Operations.CompositeOperationBuilder builder = Operations.CompositeOperationBuilder.create() + .addStep(Operations.createReadAttributeOperation(hostAddress, "running-mode")) + .addStep(Operations.createReadAttributeOperation(hostAddress, "host-state")); + ModelNode response = domainClient.execute(builder.build()); + if (Operations.isSuccessfulOutcome(response)) { + response = Operations.readResult(response); + if ("ADMIN_ONLY".equals(Operations.readResult(response.get("step-1")).asString())) { + if (Operations.isSuccessfulOutcome(response.get("step-2"))) { + final String state = Operations.readResult(response).asString(); + return !CONTROLLER_PROCESS_STATE_STARTING.equals(state) + && !CONTROLLER_PROCESS_STATE_STOPPING.equals(state); + } + } + } + final Map servers = new HashMap<>(); + final Map statuses = domainClient.getServerStatuses(); + for (ServerIdentity id : statuses.keySet()) { + final ServerStatus status = statuses.get(id); + switch (status) { + case DISABLED: + case STARTED: { + servers.put(id, status); + break; + } + } + } + if (shutdown) { + return statuses.isEmpty(); + } + return statuses.size() == servers.size(); + } catch (Exception e) { + LOGGER.trace("Interrupted determining if domain is running", e); + } + return false; + } +} diff --git a/src/main/java/org/wildfly/plugin/tools/server/DomainManager.java b/src/main/java/org/wildfly/plugin/tools/server/DomainManager.java new file mode 100644 index 0000000..85304a3 --- /dev/null +++ b/src/main/java/org/wildfly/plugin/tools/server/DomainManager.java @@ -0,0 +1,177 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugin.tools.server; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.helpers.ClientConstants; +import org.jboss.as.controller.client.helpers.Operations; +import org.jboss.as.controller.client.helpers.domain.DomainClient; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.Property; +import org.jboss.logging.Logger; +import org.wildfly.plugin.tools.OperationExecutionException; + +/** + * A utility for executing management operations on domain servers. + * + * @author James R. Perkins + */ +@SuppressWarnings("unused") +public class DomainManager extends AbstractServerManager { + private static final Logger LOGGER = Logger.getLogger(DomainManager.class); + private final DomainClient client; + + protected DomainManager(final ProcessHandle process, final DomainClient client) { + super(process, client); + this.client = client; + } + + @Override + public ModelControllerClient client() { + return client; + } + + @Override + public String serverState() { + try { + @SuppressWarnings("resource") + final ModelNode response = client() + .execute(Operations.createReadAttributeOperation(determineHostAddress(), "host-state")); + return Operations.isSuccessfulOutcome(response) ? Operations.readResult(response).asString() : "failed"; + } catch (RuntimeException | IOException e) { + LOGGER.tracef("Interrupted determining the server state", e); + } + return "failed"; + } + + /** + * Determines the address for the host being used. + * + * @return the address of the host + * + * @throws IOException if an error occurs communicating with the server + * @throws OperationExecutionException if the operation used to determine the host name fails + */ + public ModelNode determineHostAddress() throws OperationExecutionException, IOException { + return CommonOperations.determineHostAddress(client); + } + + /** + * Checks to see if the domain is running. If the server is not in admin only mode each servers running state is + * checked. If any server is not in a started state the domain is not considered to be running. + * + * @return {@code true} if the server is in a running state, otherwise {@code false} + */ + @Override + public boolean isRunning() { + return CommonOperations.isDomainRunning(client, false); + } + + @Override + public void shutdown() throws IOException, OperationExecutionException { + shutdown(0); + } + + @Override + public void shutdown(final long timeout) + throws IOException { + // Note the following two operations used to shutdown a domain don't seem to work well in a composite operation. + // The operation occasionally sees a java.util.concurrent.CancellationException because the operation client + // is likely closed before the AsyncFuture.get() is complete. Using a non-composite operation doesn't seem to + // have this issue. + + // First shutdown the servers + final ModelNode stopServersOp = Operations.createOperation("stop-servers"); + stopServersOp.get("blocking").set(true); + stopServersOp.get("timeout").set(timeout); + ModelNode response = client.execute(stopServersOp); + if (!Operations.isSuccessfulOutcome(response)) { + throw new OperationExecutionException("Failed to stop servers.", stopServersOp, response); + } + + // Now shutdown the host + final ModelNode address = determineHostAddress(); + final ModelNode shutdownOp = Operations.createOperation("shutdown", address); + response = client.execute(shutdownOp); + if (Operations.isSuccessfulOutcome(response)) { + // Wait until the process has died + while (true) { + if (CommonOperations.isDomainRunning(client, true)) { + Thread.onSpinWait(); + } else { + break; + } + } + } else { + throw new OperationExecutionException("Failed to shutdown host.", shutdownOp, response); + } + } + + @Override + public void executeReload() { + executeReload(Operations.createOperation("reload-servers")); + } + + @Override + public void reloadIfRequired() throws IOException { + reloadIfRequired(10L, TimeUnit.SECONDS); + } + + @Override + public void reloadIfRequired(final long timeout, final TimeUnit unit) throws IOException { + final String launchType = launchType(); + if ("DOMAIN".equalsIgnoreCase(launchType)) { + final Map steps = new HashMap<>(); + Operations.CompositeOperationBuilder builder = Operations.CompositeOperationBuilder.create(); + int stepCounter = 1; + final ModelNode hostAddress = determineHostAddress(); + for (var entry : client.getServerStatuses().entrySet()) { + final ModelNode address = hostAddress.clone().add("server", entry.getKey().getServerName()); + final ModelNode op = Operations.createReadAttributeOperation(address, "server-state"); + builder.addStep(op); + // We will simply record the step and address to have a mapping for the reload commands + steps.put("step-" + stepCounter++, address); + } + + // Execute the operation + ModelNode result = client.execute(builder.build()); + if (!Operations.isSuccessfulOutcome(result)) { + throw new OperationExecutionException("Failed to reload servers.", builder.build(), result); + } + // Create a new builder for each reload operation + builder = Operations.CompositeOperationBuilder.create(); + final ModelNode results = Operations.readResult(result); + for (Property serverResult : results.asPropertyList()) { + if (ClientConstants.CONTROLLER_PROCESS_STATE_RELOAD_REQUIRED + .equals(Operations.readResult(serverResult.getValue()) + .asString())) { + final ModelNode address = steps.get(serverResult.getName()); + builder.addStep(Operations.createOperation("reload", address)); + } + } + result = client.execute(builder.build()); + if (!Operations.isSuccessfulOutcome(result)) { + throw new OperationExecutionException("Failed to reload servers.", builder.build(), result); + } + try { + if (!waitFor(timeout, unit)) { + throw new RuntimeException(String.format("Failed to reload servers within %d %s.", timeout, unit.name() + .toLowerCase(Locale.ROOT))); + } + } catch (InterruptedException e) { + throw new RuntimeException("Failed to reload the servers.", e); + } + } else { + LOGGER.warnf("Cannot reload and wait for the server to start with a server type of %s.", launchType); + } + } +} diff --git a/src/main/java/org/wildfly/plugin/tools/server/ServerManager.java b/src/main/java/org/wildfly/plugin/tools/server/ServerManager.java new file mode 100644 index 0000000..0f6e827 --- /dev/null +++ b/src/main/java/org/wildfly/plugin/tools/server/ServerManager.java @@ -0,0 +1,438 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugin.tools.server; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.helpers.Operations; +import org.jboss.as.controller.client.helpers.domain.DomainClient; +import org.jboss.dmr.ModelNode; +import org.jboss.logging.Logger; +import org.wildfly.plugin.tools.ContainerDescription; +import org.wildfly.plugin.tools.DeploymentManager; + +/** + * A simple manager for various interactions with a potentially running server. + * + * @author James R. Perkins + */ +@SuppressWarnings("unused") +public interface ServerManager { + + /** + * A builder used to build a {@link ServerManager}. + */ + class Builder { + private ModelControllerClient client; + private String managementAddress; + private int managementPort; + private ProcessHandle process; + + /** + * Sets the client to use for the server manager. + * + * @param client the client to use to communicate with the server + * + * @return this builder + */ + public Builder client(final ModelControllerClient client) { + this.client = client; + return this; + } + + /** + * The process handle to associate with the server manager. + * + * @param process the process handle to associate with the server manager + * + * @return this builder + */ + public Builder process(final ProcessHandle process) { + this.process = process; + return this; + } + + /** + * The process to associate with the server manager. If the {@code process} argument is not {@code null}, this + * simply invokes {@link #process(ProcessHandle) process(process.toHandle())}. + * + * @param process the process to associate with the server manager + * + * @return this builder + * + * @see #process(ProcessHandle) + */ + public Builder process(final Process process) { + this.process = process == null ? null : process.toHandle(); + return this; + } + + /** + * The management address to use for the client if the {@linkplain #client(ModelControllerClient) client} has + * not been set. + * + * @param managementAddress the management address, default is {@code localhost} + * + * @return this builder + */ + public Builder managementAddress(final String managementAddress) { + this.managementAddress = managementAddress; + return this; + } + + /** + * The management port to use for the client if the {@linkplain #client(ModelControllerClient) client} has + * not been set. + * + * @param managementPort the management port, default is {@code 9990} + * + * @return this builder + */ + public Builder managementPort(final int managementPort) { + this.managementPort = managementPort; + return this; + } + + /** + * Creates a {@link StandaloneManager} based on the builders settings. If the + * {@link #client(ModelControllerClient) client} was not set, the {@link #managementAddress(String) managementAddress} + * and the {@link #managementPort(int) managementPort} will be used to create the client. + * + * @return a new {@link StandaloneManager} + */ + public StandaloneManager standalone() { + return new StandaloneManager(process, getOrCreateClient()); + } + + /** + * Creates a {@link DomainManager} based on the builders settings. If the + * {@link #client(ModelControllerClient) client} was not set, the {@link #managementAddress(String) managementAddress} + * and the {@link #managementPort(int) managementPort} will be used to create the client. + * + * @return a new {@link DomainManager} + */ + public DomainManager domain() { + return new DomainManager(process, getOrCreateDomainClient()); + } + + /** + * Creates either a {@link DomainManager} or {@link StandaloneManager} based on the + * {@link ServerManager#launchType(ModelControllerClient)}. If the {@link #client(ModelControllerClient) client} + * was not set, the {@link #managementAddress(String) managementAddress} and the + * {@link #managementPort(int) managementPort} will be used to create the client. + *

+ * Note that if the {@linkplain #process(ProcessHandle) process} was not set, the future may never complete + * if a server is never started. It's best practice to either use a known {@link #standalone()} or {@link #domain()} + * server manager type, or use the {@link CompletableFuture#get(long, TimeUnit)} method to timeout if a server + * was never started. + *

+ * + * @return a completable future that will eventually produce a {@link DomainManager} or {@link StandaloneManager} + * assuming a server is running + */ + public CompletableFuture build() { + final ModelControllerClient client = getOrCreateClient(); + final ProcessHandle process = this.process; + return CompletableFuture.supplyAsync(() -> { + // Wait until the server is running, then determine what type we need to return + while (!isRunning(client)) { + Thread.onSpinWait(); + } + final String launchType = launchType(client).orElseThrow(() -> new IllegalStateException( + "Could not determine the type of the server. Verify the server is running.")); + if ("STANDALONE".equals(launchType)) { + return new StandaloneManager(process, client); + } else if ("DOMAIN".equals(launchType)) { + return new DomainManager(process, getOrCreateDomainClient()); + } + throw new IllegalStateException( + String.format("Only standalone and domain servers are support. %s is not supported.", launchType)); + }); + } + + private ModelControllerClient getOrCreateClient() { + if (client == null) { + final String address = managementAddress == null ? "localhost" : managementAddress; + final int port = managementPort <= 0 ? 9990 : managementPort; + try { + return ModelControllerClient.Factory.create(address, port); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + return client; + } + + private DomainClient getOrCreateDomainClient() { + if (client == null) { + return DomainClient.Factory.create(getOrCreateClient()); + } + return (client instanceof DomainClient) ? (DomainClient) client : DomainClient.Factory.create(client); + } + } + + /** + * Creates a builder to build a server manager. + * + * @return a new builder + */ + static Builder builder() { + return new Builder(); + } + + /** + * Attempts to find the controlling process. For a domain server this, returns the process handle for the + * process controller. For a standalone server, this returns the standalone process handle. + * + * @return the process handle if one was found running + */ + static Optional findProcess() { + // Attempt to find a running server process, this may be a process controller or standalone instance + return ProcessHandle.allProcesses() + .filter(p -> { + final ProcessHandle.Info info = p.info(); + boolean found = false; + if (info.arguments().isPresent()) { + // Look for the "-jar jboss-modules.jar" argument + final String[] arguments = info.arguments().get(); + for (int i = 0; i < arguments.length; i++) { + final String arg = arguments[i]; + if (!found && arg.trim().equalsIgnoreCase("-jar")) { + found = arguments[++i].contains("jboss-modules.jar"); + continue; + } + if (found && ("org.jboss.as.process-controller").equals(arg) + || "org.jboss.as.standalone".equals(arg)) { + return true; + } + } + } + return false; + }).findFirst(); + } + + /** + * Checks whether the directory is a valid home directory for a server. + *

+ * This validates the path is not {@code null}, exists, is a directory and contains a {@code jboss-modules.jar}. + *

+ * + * @param path the path to validate + * + * @return {@code true} if the path is valid otherwise {@code false} + */ + static boolean isValidHomeDirectory(final Path path) { + return path != null + && Files.exists(path) + && Files.isDirectory(path) + && Files.exists(path.resolve("jboss-modules.jar")); + } + + /** + * Checks whether the directory is a valid home directory for a server. + *

+ * This validates the path is not {@code null}, exists, is a directory and contains a {@code jboss-modules.jar}. + *

+ * + * @param path the path to validate + * + * @return {@code true} if the path is valid otherwise {@code false} + */ + static boolean isValidHomeDirectory(final String path) { + return path != null && isValidHomeDirectory(Path.of(path)); + } + + /** + * Checks if a server is running regardless if it is a standalone or domain server. + * + * @param client the client used to check the server state + * + * @return {@code true} if a server is running, otherwise {@code false} + */ + static boolean isRunning(final ModelControllerClient client) { + try { + String launchType; + while ((launchType = launchType(client).orElse(null)) != null) { + if ("STANDALONE".equals(launchType)) { + return CommonOperations.isStandaloneRunning(client); + } else if ("DOMAIN".equals(launchType)) { + return CommonOperations.isDomainRunning(client, false); + } + } + } catch (RuntimeException e) { + Logger.getLogger(ServerManager.class).trace("Interrupted determining if server is running", e); + } + return false; + } + + /** + * Returns the "launch-type" attribute of a server. + * + * @param client the client used to check the launch-type attribute + * + * @return the servers launch-type + */ + static Optional launchType(final ModelControllerClient client) { + try { + final ModelNode response = client + .execute(Operations.createReadAttributeOperation(new ModelNode().setEmptyList(), "launch-type")); + return Operations.isSuccessfulOutcome(response) ? Optional.of(Operations.readResult(response).asString()) + : Optional.empty(); + } catch (RuntimeException | IOException ignore) { + } + return Optional.empty(); + } + + /** + * Returns the client associated with this server manager. + * + * @return a client to communicate with the server + */ + ModelControllerClient client(); + + /** + * Gets the "server-state" for standalone servers or the "host-state" for domain servers. + * + * @return the server-state or "failed" if an error occurred + */ + String serverState(); + + /** + * Determines the servers "launch-type". + * + * @return the servers launch-type or "unknown" if it could not be determined + */ + String launchType(); + + /** + * Takes a snapshot of the current servers configuration and returns the relative file name of the snapshot. + *

+ * This simply executes the {@code take-snapshot} operation with no arguments. + *

+ * + * @return the file name of the snapshot configuration file + * + * @throws IOException if an error occurs executing the operation + */ + String takeSnapshot() throws IOException; + + /** + * Returns the container description for the running server. + * + * @return the container description for the running server + * + * @throws IOException if an error occurs communicating with the server + */ + ContainerDescription containerDescription() throws IOException; + + /** + * Returns the deployment manager for the server. + * + * @return the deployment manager + */ + DeploymentManager deploymentManager(); + + /** + * Checks to see if a server is running. + * + * @return {@code true} if the server is running, otherwise {@code false} + */ + boolean isRunning(); + + /** + * Waits the given amount of time in seconds for a server to start. + *

+ * If the {@code process} is not {@code null} and a timeout occurs the process will be + * {@linkplain Process#destroy() destroyed}. + *

+ * + * @param startupTimeout the time, in seconds, to wait for the server start + * + * @return {@code true} if the server is up and running, {@code false} if a timeout occurred waiting for the + * server to be in a running state + * + * @throws InterruptedException if interrupted while waiting for the server to start + */ + default boolean waitFor(final long startupTimeout) throws InterruptedException { + return waitFor(startupTimeout, TimeUnit.SECONDS); + } + + /** + * Waits the given amount of time for a server to start. + *

+ * If the {@code process} is not {@code null} and a timeout occurs the process will be + * {@linkplain Process#destroy() destroyed}. + *

+ * + * @param startupTimeout the time, to wait for the server start + * @param unit the time unit for the {@code startupTimeout} argument + * + * @return {@code true} if the server is up and running, {@code false} if a timeout occurred waiting for the + * server to be in a running state + * + * @throws InterruptedException if interrupted while waiting for the server to start + */ + boolean waitFor(long startupTimeout, TimeUnit unit) throws InterruptedException; + + /** + * Shuts down the server. + * + * @throws IOException if an error occurs communicating with the server + */ + void shutdown() throws IOException; + + /** + * Shuts down the server. + * + * @param timeout the graceful shutdown timeout, a value of {@code -1} will wait indefinitely and a value of + * {@code 0} will not attempt a graceful shutdown + * + * @throws IOException if an error occurs communicating with the server + */ + void shutdown(long timeout) throws IOException; + + /** + * Reloads the server and returns immediately. + * + * @throws IOException if an error occurs communicating with the server + */ + void executeReload() throws IOException; + + /** + * Reloads the server and returns immediately. + * + * @param reloadOp the reload operation to execute + * + * @throws IOException if an error occurs communicating with the server + */ + void executeReload(final ModelNode reloadOp) throws IOException; + + /** + * Checks if the container status is "reload-required" and if it's the case, executes reload and waits for + * completion with a 10 second timeout. + * + * @throws IOException if an error occurs communicating with the server + * @see #reloadIfRequired(long, TimeUnit) + */ + void reloadIfRequired() throws IOException; + + /** + * Checks if the container status is "reload-required" and if it's the case, executes reload and waits for completion. + * + * @param timeout the time to wait for the server to reload + * @param unit the time unit for the {@code timeout} argument + * + * @throws IOException if an error occurs communicating with the server + */ + void reloadIfRequired(final long timeout, final TimeUnit unit) throws IOException; +} diff --git a/src/main/java/org/wildfly/plugin/tools/server/StandaloneManager.java b/src/main/java/org/wildfly/plugin/tools/server/StandaloneManager.java new file mode 100644 index 0000000..52e8835 --- /dev/null +++ b/src/main/java/org/wildfly/plugin/tools/server/StandaloneManager.java @@ -0,0 +1,109 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugin.tools.server; + +import java.io.IOException; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.helpers.Operations; +import org.jboss.dmr.ModelNode; +import org.jboss.logging.Logger; +import org.wildfly.plugin.tools.OperationExecutionException; + +/** + * A utility for managing a standalone server. + * + * @author James R. Perkins + */ +@SuppressWarnings("unused") +public class StandaloneManager extends AbstractServerManager { + private static final Logger LOGGER = Logger.getLogger(StandaloneManager.class); + private final ModelControllerClient client; + + protected StandaloneManager(final ProcessHandle process, final ModelControllerClient client) { + super(process, client); + this.client = client; + } + + @Override + public ModelControllerClient client() { + return client; + } + + @Override + public String serverState() { + try { + @SuppressWarnings("resource") + final ModelNode response = client() + .execute(Operations.createReadAttributeOperation(CommonOperations.EMPTY_ADDRESS, "server-state")); + return Operations.isSuccessfulOutcome(response) ? Operations.readResult(response).asString() : "failed"; + } catch (RuntimeException | IOException e) { + LOGGER.tracef("Interrupted determining the server state", e); + } + return "failed"; + } + + @Override + public void executeReload() throws IOException { + executeReload(Operations.createOperation("reload")); + } + + @Override + public void reloadIfRequired() throws IOException { + reloadIfRequired(10L, TimeUnit.SECONDS); + } + + @Override + public void reloadIfRequired(final long timeout, final TimeUnit unit) throws IOException { + final String launchType = launchType(); + if ("STANDALONE".equalsIgnoreCase(launchType)) { + final String runningState = serverState(); + if ("reload-required".equalsIgnoreCase(runningState)) { + executeReload(); + try { + if (!waitFor(timeout, unit)) { + throw new RuntimeException(String.format("Failed to reload server within %d %s.", timeout, unit.name() + .toLowerCase(Locale.ROOT))); + } + } catch (InterruptedException e) { + throw new RuntimeException("Failed to reload the server.", e); + } + } + } else { + LOGGER.warnf("Cannot reload and wait for the server to start with a server type of %s.", launchType); + } + } + + @Override + public boolean isRunning() { + return CommonOperations.isStandaloneRunning(client); + } + + @Override + public void shutdown() throws IOException { + shutdown(0); + } + + @Override + public void shutdown(final long timeout) throws IOException { + final ModelNode op = Operations.createOperation("shutdown"); + op.get("timeout").set(timeout); + final ModelNode response = client.execute(op); + if (Operations.isSuccessfulOutcome(response)) { + while (true) { + if (isRunning()) { + Thread.onSpinWait(); + } else { + break; + } + } + } else { + throw new OperationExecutionException(op, response); + } + } +} diff --git a/src/test/java/org/wildfly/plugin/tools/AbstractDeploymentManagerTest.java b/src/test/java/org/wildfly/plugin/tools/AbstractDeploymentManagerTest.java index b84e135..54b36ee 100644 --- a/src/test/java/org/wildfly/plugin/tools/AbstractDeploymentManagerTest.java +++ b/src/test/java/org/wildfly/plugin/tools/AbstractDeploymentManagerTest.java @@ -180,7 +180,7 @@ public void testForceDeployMulti() throws Exception { Assertions.assertTrue(first.keySet().containsAll(second.keySet())); // Skip time checks on domain until WFCORE-1667 is fixed - final boolean checkTime = !ServerHelper.getContainerDescription(getClient()).isDomain(); + final boolean checkTime = !ContainerDescription.lookup(getClient()).isDomain(); // Get the current hash for (Deployment deployment : deployments) { final byte[] hash = first.get(deployment).hash; @@ -286,7 +286,7 @@ public void testRedeployMulti() throws Exception { Assertions.assertTrue(deployResults.keySet().containsAll(currentDeployResults.keySet())); // Skip time checks on domain until WFCORE-1667 is fixed - final boolean checkTime = !ServerHelper.getContainerDescription(getClient()).isDomain(); + final boolean checkTime = !ContainerDescription.lookup(getClient()).isDomain(); for (Deployment deployment : allDeployments) { final DeployResult deployResult = deployResults.get(deployment); @@ -386,7 +386,7 @@ public void testRedeployToRuntimeMulti() throws Exception { Assertions.assertTrue(deployResults.keySet().containsAll(currentDeployResults.keySet())); // Skip time checks on domain until WFCORE-1667 is fixed - final boolean checkTime = !ServerHelper.getContainerDescription(getClient()).isDomain(); + final boolean checkTime = !ContainerDescription.lookup(getClient()).isDomain(); for (Deployment deployment : allDeployments) { final DeployResult deployResult = deployResults.get(deployment); @@ -654,7 +654,7 @@ Deployment configureDeployment(final Deployment deployment) { private byte[] readDeploymentHash(final String deploymentName) throws IOException { final ModelNode op = Operations.createReadAttributeOperation( - DeploymentOperations.createAddress(ClientConstants.DEPLOYMENT, deploymentName), ClientConstants.CONTENT); + Operations.createAddress(ClientConstants.DEPLOYMENT, deploymentName), ClientConstants.CONTENT); // Response should be a list, we only need the first entry final ModelNode response = executeOp(op).get(0); if (response.hasDefined("hash")) { diff --git a/src/test/java/org/wildfly/plugin/tools/DomainDeploymentManagerIT.java b/src/test/java/org/wildfly/plugin/tools/DomainDeploymentManagerIT.java index 44aa3ec..baf0b11 100644 --- a/src/test/java/org/wildfly/plugin/tools/DomainDeploymentManagerIT.java +++ b/src/test/java/org/wildfly/plugin/tools/DomainDeploymentManagerIT.java @@ -23,6 +23,8 @@ import org.wildfly.core.launcher.DomainCommandBuilder; import org.wildfly.core.launcher.Launcher; import org.wildfly.core.launcher.ProcessHelper; +import org.wildfly.plugin.tools.server.DomainManager; +import org.wildfly.plugin.tools.server.ServerManager; /** * @author James R. Perkins @@ -57,6 +59,7 @@ public class DomainDeploymentManagerIT extends AbstractDeploymentManagerTest { private static Process process; private static DomainClient client; + private static DomainManager domainManager; private static Thread consoleConsomer; @BeforeAll @@ -64,8 +67,8 @@ public static void startServer() throws Exception { boolean ok = false; try { client = DomainClient.Factory.create(Environment.createClient()); - if (ServerHelper.isDomainRunning(client) || ServerHelper.isStandaloneRunning(client)) { - Assertions.fail("A WildFly server is already running: " + ServerHelper.getContainerDescription(client)); + if (ServerManager.isRunning(client)) { + Assertions.fail("A WildFly server is already running: " + ContainerDescription.lookup(client)); } final DomainCommandBuilder commandBuilder = DomainCommandBuilder.of(Environment.WILDFLY_HOME); if (IS_MODULAR_JDK) { @@ -73,8 +76,8 @@ public static void startServer() throws Exception { } process = Launcher.of(commandBuilder).launch(); consoleConsomer = ConsoleConsumer.start(process, System.out); - ServerHelper.waitForDomain(client, Environment.TIMEOUT); - ok = true; + domainManager = ServerManager.builder().process(process).client(client).domain(); + ok = domainManager.waitFor(Environment.TIMEOUT); } finally { if (!ok) { final Process p = process; @@ -95,7 +98,7 @@ public static void startServer() throws Exception { public static void shutdown() throws Exception { try { if (client != null) { - ServerHelper.shutdownDomain(client); + domainManager.shutdown(); safeClose(client); } } finally { @@ -184,7 +187,7 @@ protected ModelControllerClient getClient() { @Override protected ModelNode createDeploymentResourceAddress(final String deploymentName) throws IOException { - return ServerHelper.determineHostAddress(getClient()) + return domainManager.determineHostAddress() .add(ClientConstants.SERVER, "server-one") .add(ClientConstants.DEPLOYMENT, deploymentName); } diff --git a/src/test/java/org/wildfly/plugin/tools/Environment.java b/src/test/java/org/wildfly/plugin/tools/Environment.java index 4d1acda..ece8d88 100644 --- a/src/test/java/org/wildfly/plugin/tools/Environment.java +++ b/src/test/java/org/wildfly/plugin/tools/Environment.java @@ -13,6 +13,7 @@ import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.logging.Logger; +import org.wildfly.plugin.tools.server.ServerManager; import org.wildfly.plugin.tools.util.Utils; /** @@ -81,7 +82,7 @@ public static ModelControllerClient createClient() throws UnknownHostException { } private static void validateWildFlyHome(final Path wildflyHome) { - if (!ServerHelper.isValidHomeDirectory(wildflyHome)) { + if (!ServerManager.isValidHomeDirectory(wildflyHome)) { throw new RuntimeException("Invalid WildFly home directory: " + wildflyHome); } } diff --git a/src/test/java/org/wildfly/plugin/tools/ServerManagerIT.java b/src/test/java/org/wildfly/plugin/tools/ServerManagerIT.java new file mode 100644 index 0000000..cb8f439 --- /dev/null +++ b/src/test/java/org/wildfly/plugin/tools/ServerManagerIT.java @@ -0,0 +1,177 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugin.tools; + +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.helpers.ClientConstants; +import org.jboss.as.controller.client.helpers.Operations; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.Property; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.wildfly.core.launcher.DomainCommandBuilder; +import org.wildfly.core.launcher.Launcher; +import org.wildfly.core.launcher.StandaloneCommandBuilder; +import org.wildfly.plugin.tools.server.DomainManager; +import org.wildfly.plugin.tools.server.ServerManager; +import org.wildfly.plugin.tools.server.StandaloneManager; + +/** + * @author James R. Perkins + */ +public class ServerManagerIT { + + @Test + public void findDomainProcess() throws Exception { + checkProcess(launchDomain()); + } + + @Test + public void findStandaloneProcess() throws Exception { + checkProcess(launchStandalone()); + } + + @Test + public void checkDomainServerState() throws Exception { + checkServerState(launchDomain()); + } + + @Test + public void checkStandaloneServerState() throws Exception { + checkServerState(launchStandalone()); + } + + @Test + public void checkStandaloneReloadIfRequired() throws Exception { + final Process process = launchStandalone(); + try (ModelControllerClient client = Environment.createClient()) { + final StandaloneManager serverManager = ServerManager.builder() + .process(process) + .client(client) + .standalone(); + serverManager.waitFor(Environment.TIMEOUT, TimeUnit.SECONDS); + // Execute a command which will put the server in a state of requiring a reload + final ModelNode address = Operations.createAddress("subsystem", "remoting"); + ModelNode result = executeCommand(client, + Operations.createWriteAttributeOperation(address, "max-inbound-channels", 50)); + verifyReloadRequired(result); + serverManager.reloadIfRequired(); + Assertions.assertTrue(serverManager.isRunning(), "The server does not appear to be running."); + // Validate the server state + result = executeCommand(client, + Operations.createReadAttributeOperation(new ModelNode().setEmptyList(), "server-state")); + Assertions.assertEquals(ClientConstants.CONTROLLER_PROCESS_STATE_RUNNING, Operations.readResult(result) + .asString()); + } finally { + process.destroyForcibly(); + } + } + + @Test + public void checkDomainReloadIfRequired() throws Exception { + final Process process = launchDomain(); + try (ModelControllerClient client = Environment.createClient()) { + final DomainManager serverManager = ServerManager.builder().process(process).client(client).domain(); + serverManager.waitFor(Environment.TIMEOUT, TimeUnit.SECONDS); + // Execute a command which will put the server in a state of requiring a reload + final ModelNode address = Operations.createAddress("profile", "full", "subsystem", "remoting"); + ModelNode result = executeCommand(client, + Operations.createWriteAttributeOperation(address, "max-inbound-channels", 50)); + verifyReloadRequired(result); + serverManager.reloadIfRequired(); + Assertions.assertTrue(serverManager.isRunning(), "The server does not appear to be running."); + // Validate the server state + result = executeCommand(client, + Operations.createReadAttributeOperation(serverManager.determineHostAddress() + .add("server", "server-one"), + "server-state")); + Assertions.assertEquals(ClientConstants.CONTROLLER_PROCESS_STATE_RUNNING, Operations.readResult(result) + .asString()); + } finally { + process.destroyForcibly(); + } + } + + private ModelNode executeCommand(final ModelControllerClient client, final ModelNode op) throws IOException { + final ModelNode result = client.execute(op); + if (!Operations.isSuccessfulOutcome(result)) { + Assertions.fail("Failed to execute command: " + Operations.getFailureDescription(result)); + } + return result; + } + + private void verifyReloadRequired(final ModelNode result) { + if (result.hasDefined(ClientConstants.RESPONSE_HEADERS)) { + final ModelNode responseHeaders = result.get(ClientConstants.RESPONSE_HEADERS); + Assertions.assertTrue(responseHeaders.hasDefined("operation-requires-reload") && + responseHeaders.get("operation-requires-reload").asBoolean(), + "The operation did not require a reload: " + responseHeaders); + } else if (result.hasDefined("server-groups")) { + // Check the server groups for the response headers + for (Property property : result.get("server-groups").asPropertyList()) { + // They key is the server name and the value is the response for that server + for (ModelNode serverNode : property.getValue().get("host", "primary").asList()) { + verifyReloadRequired(serverNode.asProperty().getValue().get("response")); + } + } + } else { + Assertions.fail("The operation did not require a reload: " + result); + } + } + + private void checkServerState(final Process process) throws Exception { + try (ModelControllerClient client = Environment.createClient()) { + final ServerManager serverManager = ServerManager.builder().process(process).client(client).build() + .get(Environment.TIMEOUT, TimeUnit.SECONDS); + try { + Assertions.assertTrue(serverManager.waitFor(Environment.TIMEOUT), "Server failed to start"); + // Check the server state + Assertions.assertEquals("running", serverManager.serverState()); + } finally { + serverManager.shutdown(); + } + } finally { + process.destroyForcibly(); + } + } + + private void checkProcess(final Process process) throws Exception { + try (ModelControllerClient client = Environment.createClient()) { + final ServerManager serverManager = ServerManager.builder().process(process).client(client).build() + .get(Environment.TIMEOUT, TimeUnit.SECONDS); + try { + Assertions.assertTrue(serverManager.waitFor(Environment.TIMEOUT), "Server failed to start"); + final Optional handle = ServerManager.findProcess(); + Assertions.assertTrue(handle.isPresent(), () -> "Could not find the server process for " + process.pid()); + Assertions.assertEquals(process.toHandle(), handle.get()); + } finally { + serverManager.shutdown(); + } + } finally { + process.destroyForcibly(); + } + } + + private Process launchDomain() throws IOException { + final Process process = Launcher.of(DomainCommandBuilder.of(Environment.WILDFLY_HOME)) + .setRedirectErrorStream(true) + .launch(); + ConsoleConsumer.start(process, System.out); + return process; + } + + private Process launchStandalone() throws IOException { + final Process process = Launcher.of(StandaloneCommandBuilder.of(Environment.WILDFLY_HOME)) + .setRedirectErrorStream(true) + .launch(); + ConsoleConsumer.start(process, System.out); + return process; + } +} diff --git a/src/test/java/org/wildfly/plugin/tools/StandaloneDeploymentManagerIT.java b/src/test/java/org/wildfly/plugin/tools/StandaloneDeploymentManagerIT.java index 94ee2f8..49bd298 100644 --- a/src/test/java/org/wildfly/plugin/tools/StandaloneDeploymentManagerIT.java +++ b/src/test/java/org/wildfly/plugin/tools/StandaloneDeploymentManagerIT.java @@ -9,6 +9,7 @@ import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.as.controller.client.helpers.ClientConstants; +import org.jboss.as.controller.client.helpers.Operations; import org.jboss.dmr.ModelNode; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; @@ -17,6 +18,7 @@ import org.wildfly.core.launcher.Launcher; import org.wildfly.core.launcher.ProcessHelper; import org.wildfly.core.launcher.StandaloneCommandBuilder; +import org.wildfly.plugin.tools.server.ServerManager; /** * @author James R. Perkins @@ -26,6 +28,7 @@ public class StandaloneDeploymentManagerIT extends AbstractDeploymentManagerTest private static Process process; private static ModelControllerClient client; + private static ServerManager serverManager; private static Thread consoleConsomer; @BeforeAll @@ -33,14 +36,14 @@ public static void startServer() throws Exception { boolean ok = false; try { client = Environment.createClient(); - if (ServerHelper.isDomainRunning(client) || ServerHelper.isStandaloneRunning(client)) { - Assertions.fail("A WildFly server is already running: " + ServerHelper.getContainerDescription(client)); + if (ServerManager.isRunning(client)) { + Assertions.fail("A WildFly server is already running: " + ContainerDescription.lookup(client)); } final StandaloneCommandBuilder commandBuilder = StandaloneCommandBuilder.of(Environment.WILDFLY_HOME); process = Launcher.of(commandBuilder).launch(); consoleConsomer = ConsoleConsumer.start(process, System.out); - ServerHelper.waitForStandalone(client, Environment.TIMEOUT); - ok = true; + serverManager = ServerManager.builder().process(process).client(client).standalone(); + ok = serverManager.waitFor(Environment.TIMEOUT); } finally { if (!ok) { final Process p = process; @@ -61,7 +64,7 @@ public static void startServer() throws Exception { public static void shutdown() throws Exception { try { if (client != null) { - ServerHelper.shutdownStandalone(client); + serverManager.shutdown(); safeClose(client); } } finally { @@ -91,6 +94,6 @@ protected ModelControllerClient getClient() { @Override protected ModelNode createDeploymentResourceAddress(final String deploymentName) throws IOException { - return DeploymentOperations.createAddress(ClientConstants.DEPLOYMENT, deploymentName); + return Operations.createAddress(ClientConstants.DEPLOYMENT, deploymentName); } } diff --git a/src/test/java/org/wildfly/plugin/tools/bootablejar/BootLoggingConfigurationIT.java b/src/test/java/org/wildfly/plugin/tools/bootablejar/BootLoggingConfigurationIT.java index cc276a7..2bb5b9e 100644 --- a/src/test/java/org/wildfly/plugin/tools/bootablejar/BootLoggingConfigurationIT.java +++ b/src/test/java/org/wildfly/plugin/tools/bootablejar/BootLoggingConfigurationIT.java @@ -41,7 +41,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.regex.Pattern; import org.jboss.as.controller.client.ModelControllerClient; @@ -60,7 +59,7 @@ import org.wildfly.core.launcher.Launcher; import org.wildfly.core.launcher.StandaloneCommandBuilder; import org.wildfly.plugin.tools.Environment; -import org.wildfly.plugin.tools.ServerHelper; +import org.wildfly.plugin.tools.server.ServerManager; /** * @author James R. Perkins @@ -71,6 +70,7 @@ public class BootLoggingConfigurationIT { private static Process currentProcess; private static Path stdout; private static ModelControllerClient client; + private static ServerManager serverManager; private final Deque tearDownOps = new ArrayDeque<>(); private Path tmpDir; @@ -85,16 +85,16 @@ public static void startWildFly() throws Exception { .redirectOutput(stdout) .launch(); client = ModelControllerClient.Factory.create(Environment.HOSTNAME, Environment.PORT); + serverManager = ServerManager.builder().process(currentProcess).client(client).standalone(); // Wait for standalone to start - ServerHelper.waitForStandalone(currentProcess, client, Environment.TIMEOUT); - Assertions.assertTrue(ServerHelper.isStandaloneRunning(client), + Assertions.assertTrue(serverManager.waitFor(Environment.TIMEOUT), () -> String.format("Standalone server is not running:%n%s", getLog())); } @AfterAll public static void shutdown() throws Exception { if (client != null) { - ServerHelper.shutdownStandalone(client); + serverManager.shutdown(); client.close(); } if (currentProcess != null) { @@ -727,8 +727,9 @@ private static ModelNode executeOperation(final Operation op) throws IOException .equals(responseHeaders.get("process-state").asString())) { executeOperation(Operations.createOperation("reload")); try { - ServerHelper.waitForStandalone(currentProcess, client, Environment.TIMEOUT); - } catch (InterruptedException | TimeoutException e) { + Assertions.assertTrue(serverManager.waitFor(Environment.TIMEOUT), + String.format("The server did not start within %s seconds", Environment.TIMEOUT)); + } catch (InterruptedException e) { final StringWriter writer = new StringWriter(); e.printStackTrace(new PrintWriter(writer)); Assertions.fail("Reloading the server failed: " + writer);