package org.wildfly.test.suspendresumeendpoint; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.as.network.SocketBindingManager; import org.wildfly.extension.requestcontroller.ControlPoint; import org.wildfly.extension.requestcontroller.RequestController; import org.wildfly.extension.requestcontroller.RunResult; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; import org.jboss.msc.value.InjectedValue; import io.undertow.Undertow; import io.undertow.server.ExchangeCompletionListener; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; /** * @author Stuart Douglas */ public class TestUndertowService implements Service<TestUndertowService> { private static final AtomicInteger COUNT = new AtomicInteger(); public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("test-undertow-server"); public static final String SKIP_GRACEFUL = "skip-graceful"; private volatile Undertow undertow; private final InjectedValue<RequestController> requestControllerInjectedValue = new InjectedValue<>(); private final InjectedValue<SocketBindingManager> socketBindingManagerInjectedValue = new InjectedValue<>(); @Override public void start(StartContext context) throws StartException { //add graceful shutdown support final SuspendResumeHandler suspendResumeHandler = new SuspendResumeHandler(); final ControlPoint controlPoint = requestControllerInjectedValue.getValue().getControlPoint("test", "test"); final ExchangeCompletionListener exchangeCompletionListener = new ExchangeCompletionListener() { @Override public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) { controlPoint.requestComplete(); nextListener.proceed(); } }; HttpHandler shutdown = new HttpHandler() { @Override public void handleRequest(final HttpServerExchange exchange) throws Exception { if(exchange.isInIoThread()) { exchange.dispatch(this); return; } final int count = COUNT.incrementAndGet(); if(exchange.getQueryParameters().containsKey(SKIP_GRACEFUL)) { //bit of a hack, allows to send in some requests even when the server is paused //very useful for testing System.out.println("Skipping request " + count + " " + exchange); suspendResumeHandler.handleRequest(exchange); return; } System.out.println("Attempting " + count + " " + exchange); RunResult result = controlPoint.beginRequest(); if (result == RunResult.REJECTED) { exchange.dispatch(new Runnable() { @Override public void run() { controlPoint.queueTask(new Runnable() { @Override public void run() { exchange.addExchangeCompleteListener(exchangeCompletionListener); exchange.dispatch(suspendResumeHandler); } }, exchange.getIoThread(), 1000, new Runnable() { @Override public void run() { System.out.println("Rejected " + count + " " + exchange); exchange.setStatusCode(503); exchange.endExchange(); } }, true); } }); return; } exchange.addExchangeCompleteListener(exchangeCompletionListener); suspendResumeHandler.handleRequest(exchange); } }; undertow = Undertow.builder().addHttpListener(8080 + socketBindingManagerInjectedValue.getValue().getPortOffset(), "0.0.0.0").setHandler(shutdown).build(); undertow.start(); } @Override public void stop(StopContext context) { undertow.stop(); undertow = null; } @Override public TestUndertowService getValue() throws IllegalStateException, IllegalArgumentException { return this; } public InjectedValue<RequestController> getRequestControllerInjectedValue() { return requestControllerInjectedValue; } public InjectedValue<SocketBindingManager> getSocketBindingManagerInjectedValue() { return socketBindingManagerInjectedValue; } }