diff --git a/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java b/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java index 0d21ece37f..1a488d359c 100644 --- a/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java +++ b/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java @@ -612,26 +612,28 @@ public HttpHandler call(HttpServerExchange exchange, Object ignore) throws Servl @Override public void stop() throws ServletException { - try { - deployment.createThreadSetupAction(new ThreadSetupHandler.Action() { - @Override - public Void call(HttpServerExchange exchange, Object ignore) throws ServletException { - for (Lifecycle object : deployment.getLifecycleObjects()) { - try { - object.stop(); - } catch (Throwable t) { - UndertowServletLogger.ROOT_LOGGER.failedToDestroy(object, t); + if(deployment.getDeploymentState() == State.STARTED) { + try { + deployment.createThreadSetupAction(new ThreadSetupHandler.Action() { + @Override + public Void call(HttpServerExchange exchange, Object ignore) throws ServletException { + for (Lifecycle object : deployment.getLifecycleObjects()) { + try { + object.stop(); + } catch (Throwable t) { + UndertowServletLogger.ROOT_LOGGER.failedToDestroy(object, t); + } } + deployment.getSessionManager().stop(); + state = State.DEPLOYED; + return null; } - deployment.getSessionManager().stop(); - state = State.DEPLOYED; - return null; - } - }).call(null, null); - } catch (ServletException|RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); + }).call(null, null); + } catch (ServletException|RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } } } @@ -669,27 +671,29 @@ public void handleDeploymentSessionConfig(DeploymentInfo deploymentInfo, Servlet @Override public void undeploy() { - try { - deployment.createThreadSetupAction(new ThreadSetupHandler.Action() { - @Override - public Void call(HttpServerExchange exchange, Object ignore) throws ServletException { - for(ServletContextListener listener : deployment.getDeploymentInfo().getDeploymentCompleteListeners()) { - try { - listener.contextDestroyed(new ServletContextEvent(deployment.getServletContext())); - } catch (Throwable t) { - UndertowServletLogger.REQUEST_LOGGER.failedToDestroy(listener, t); + if(deployment.getDeploymentState() == State.DEPLOYED) { + //NOTE: this can happen if deployment isnt full and attempt is made to roll it back. + try { + deployment.createThreadSetupAction(new ThreadSetupHandler.Action() { + @Override + public Void call(HttpServerExchange exchange, Object ignore) throws ServletException { + for(ServletContextListener listener : deployment.getDeploymentInfo().getDeploymentCompleteListeners()) { + try { + listener.contextDestroyed(new ServletContextEvent(deployment.getServletContext())); + } catch (Throwable t) { + UndertowServletLogger.REQUEST_LOGGER.failedToDestroy(listener, t); + } } + deployment.destroy(); + deployment = null; + state = State.UNDEPLOYED; + return null; } - deployment.destroy(); - deployment = null; - state = State.UNDEPLOYED; - return null; - } - }).call(null, null); - } catch (Exception e) { - throw new RuntimeException(e); + }).call(null, null); + } catch (Exception e) { + throw new RuntimeException(e); + } } - } @Override diff --git a/websockets-jsr/src/test/java/io/undertow/websockets/jsr/test/annotated/BadAnnotatedEndpointTestCase.java b/websockets-jsr/src/test/java/io/undertow/websockets/jsr/test/annotated/BadAnnotatedEndpointTestCase.java new file mode 100644 index 0000000000..ef1aee4f64 --- /dev/null +++ b/websockets-jsr/src/test/java/io/undertow/websockets/jsr/test/annotated/BadAnnotatedEndpointTestCase.java @@ -0,0 +1,100 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2024 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.undertow.websockets.jsr.test.annotated; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.DeploymentManager; +import io.undertow.servlet.api.ServletContainer; +import io.undertow.servlet.test.util.TestClassIntrospector; +import io.undertow.servlet.test.util.TestResourceLoader; +import io.undertow.testutils.DefaultServer; +import io.undertow.testutils.HttpOneOnly; +import io.undertow.websockets.jsr.ServerWebSocketContainer; +import io.undertow.websockets.jsr.WebSocketDeploymentInfo; +import jakarta.servlet.ServletException; +import jakarta.websocket.DeploymentException; +import jakarta.websocket.server.ServerEndpointConfig; + +import static org.hamcrest.core.IsInstanceOf.instanceOf; +/** + * @author baranowb + */ +@RunWith(DefaultServer.class) +@HttpOneOnly +public class BadAnnotatedEndpointTestCase { + + private static ServerWebSocketContainer deployment; + private static DeploymentManager deploymentManager; + + @BeforeClass + public static void setup() throws Exception { + + final ServletContainer container = ServletContainer.Factory.newInstance(); + + DeploymentInfo builder = new DeploymentInfo() + .setClassLoader(BadAnnotatedEndpointTestCase.class.getClassLoader()).setContextPath("/ws") + .setResourceManager(new TestResourceLoader(BadAnnotatedEndpointTestCase.class)) + .setClassIntrospecter(TestClassIntrospector.INSTANCE) + .addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, + new WebSocketDeploymentInfo() + .setBuffers(DefaultServer.getBufferPool()) + .setWorker(DefaultServer.getWorkerSupplier()) + .addEndpoint(BadOnMessageEndpoint.class) + .addListener(readyContainer -> deployment = readyContainer) + .addEndpoint(ServerEndpointConfig.Builder.create( + AnnotatedAddedProgrammaticallyEndpoint.class, + AnnotatedAddedProgrammaticallyEndpoint.PATH) + .build()) + ) + .setDeploymentName("servletContext.war"); + + + deploymentManager = container.addDeployment(builder); + + } + + @AfterClass + public static void after() throws ServletException { + if (deployment != null) { + deployment.close(); + deployment = null; + } + if (deploymentManager != null) { + deploymentManager.stop(); + deploymentManager.undeploy(); + } + } + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void testStringOnMessage() throws Exception { + thrown.expect(RuntimeException.class); + thrown.expectMessage("jakarta.websocket.DeploymentException: UT003012: Method public int io.undertow.websockets.jsr.test.annotated.BadOnMessageEndpoint.handleMessage(int,jakarta.websocket.EndpointConfig) has invalid parameters at locations [1]"); + thrown.expectCause(instanceOf(DeploymentException.class)); + deploymentManager.deploy(); + } +} \ No newline at end of file diff --git a/websockets-jsr/src/test/java/io/undertow/websockets/jsr/test/annotated/BadOnMessageEndpoint.java b/websockets-jsr/src/test/java/io/undertow/websockets/jsr/test/annotated/BadOnMessageEndpoint.java new file mode 100644 index 0000000000..d0208c9e45 --- /dev/null +++ b/websockets-jsr/src/test/java/io/undertow/websockets/jsr/test/annotated/BadOnMessageEndpoint.java @@ -0,0 +1,47 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2024 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.undertow.websockets.jsr.test.annotated; + +import jakarta.websocket.EndpointConfig; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.PathParam; +import jakarta.websocket.server.ServerEndpoint; + +/** + * @author baranowb + */ +@ServerEndpoint("/increment/{increment}") +public class BadOnMessageEndpoint { + + int increment; + + @OnOpen + public void open(final Session session, final EndpointConfig config, @PathParam("increment") int increment) { + this.increment = increment; + } + + @OnMessage + public int handleMessage(final int message, EndpointConfig config) { + System.err.println("---> "+config); + return message + increment; + } + +}