From 97fd550d151c9ca914ca092a550c09c2d2f40c50 Mon Sep 17 00:00:00 2001 From: Abhinand Sundararajan Date: Mon, 3 Nov 2025 17:06:16 +0530 Subject: [PATCH 1/3] feat: add flexible samples --- .../java-25/micronaut-helloworld/README.md | 16 ++ .../micronaut-helloworld/micronaut-cli.yml | 19 ++ flexible/java-25/micronaut-helloworld/pom.xml | 188 ++++++++++++++++ .../src/main/appengine/app.yaml | 27 +++ .../com/example/appengine/Application.java | 26 +++ .../example/appengine/HelloController.java | 31 +++ .../src/main/resources/application.yml | 17 ++ .../src/main/resources/logback.xml | 28 +++ .../appengine/HelloControllerTest.java | 56 +++++ flexible/java-25/websocket-jetty/README.md | 54 +++++ flexible/java-25/websocket-jetty/pom.xml | 208 ++++++++++++++++++ .../src/main/appengine/app.yaml | 33 +++ .../websocket/jettynative/ClientSocket.java | 62 ++++++ .../websocket/jettynative/EchoServlet.java | 44 ++++ .../flexible/websocket/jettynative/Main.java | 149 +++++++++++++ .../websocket/jettynative/SendServlet.java | 143 ++++++++++++ .../websocket/jettynative/ServerSocket.java | 62 ++++++ .../src/main/webapp/WEB-INF/index.jsp | 33 +++ .../src/main/webapp/WEB-INF/jetty-web.xml | 24 ++ .../src/main/webapp/WEB-INF/js_client.jsp | 85 +++++++ .../jettynative/ClientSocketTest.java | 38 ++++ .../jettynative/SendServletTest.java | 28 +++ 22 files changed, 1371 insertions(+) create mode 100644 flexible/java-25/micronaut-helloworld/README.md create mode 100644 flexible/java-25/micronaut-helloworld/micronaut-cli.yml create mode 100644 flexible/java-25/micronaut-helloworld/pom.xml create mode 100644 flexible/java-25/micronaut-helloworld/src/main/appengine/app.yaml create mode 100644 flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/Application.java create mode 100644 flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/HelloController.java create mode 100644 flexible/java-25/micronaut-helloworld/src/main/resources/application.yml create mode 100644 flexible/java-25/micronaut-helloworld/src/main/resources/logback.xml create mode 100644 flexible/java-25/micronaut-helloworld/src/test/java/com/example/appengine/HelloControllerTest.java create mode 100644 flexible/java-25/websocket-jetty/README.md create mode 100644 flexible/java-25/websocket-jetty/pom.xml create mode 100644 flexible/java-25/websocket-jetty/src/main/appengine/app.yaml create mode 100644 flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ClientSocket.java create mode 100644 flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/EchoServlet.java create mode 100644 flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java create mode 100644 flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/SendServlet.java create mode 100644 flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ServerSocket.java create mode 100644 flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/index.jsp create mode 100644 flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/jetty-web.xml create mode 100644 flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/js_client.jsp create mode 100644 flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/ClientSocketTest.java create mode 100644 flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/SendServletTest.java diff --git a/flexible/java-25/micronaut-helloworld/README.md b/flexible/java-25/micronaut-helloworld/README.md new file mode 100644 index 00000000000..72c32c4383f --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/README.md @@ -0,0 +1,16 @@ +# Micronaut Application on Google App Engine Flex with Java 25 + +This sample shows how to deploy a [Micronaut](https://micronaut.io/) +application to Google App Engine Flex. + +## Deploying + +```bash +gcloud app deploy +``` + +To view your app, use command: +``` +gcloud app browse +``` +Or navigate to `https://.appspot.com`. diff --git a/flexible/java-25/micronaut-helloworld/micronaut-cli.yml b/flexible/java-25/micronaut-helloworld/micronaut-cli.yml new file mode 100644 index 00000000000..2c08db76694 --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/micronaut-cli.yml @@ -0,0 +1,19 @@ +# Copyright 2023 Google LLC +# +# 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. + +profile: service +defaultPackage: com.example.appengine +--- +testFramework: junit +sourceLanguage: java diff --git a/flexible/java-25/micronaut-helloworld/pom.xml b/flexible/java-25/micronaut-helloworld/pom.xml new file mode 100644 index 00000000000..8657747cee9 --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/pom.xml @@ -0,0 +1,188 @@ + + + + 4.0.0 + com.example.appengine.flexible + micronaut-helloworld + 0.1 + + + + com.google.cloud.samples + shared-configuration + 1.2.0 + + + + UTF-8 + com.example.appengine.Application + 21 + 21 + 3.10.3 + + + + + io.micronaut + micronaut-inject + ${micronaut.version} + compile + + + io.micronaut + micronaut-validation + ${micronaut.version} + compile + + + io.micronaut + micronaut-runtime + ${micronaut.version} + compile + + + io.micronaut + micronaut-http-client + ${micronaut.version} + compile + + + javax.annotation + javax.annotation-api + 1.3.2 + compile + + + io.micronaut + micronaut-http-server-netty + ${micronaut.version} + compile + + + junit + junit + 4.13.2 + test + + + + + + + com.google.cloud.tools + appengine-maven-plugin + 2.8.0 + + GCLOUD_CONFIG + micronaut-helloworld + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.1 + + + package + + shade + + + + + ${exec.mainClass} + + + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.1 + + java + + -noverify + -XX:TieredStopAtLevel=1 + -Dcom.sun.management.jmxremote + -classpath + + ${exec.mainClass} + + + + + maven-surefire-plugin + 3.2.5 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.12.1 + + UTF-8 + + -parameters + + + + io.micronaut + micronaut-inject-java + ${micronaut.version} + + + io.micronaut + micronaut-validation + ${micronaut.version} + + + + + + test-compile + + testCompile + + + + -parameters + + + + io.micronaut + micronaut-inject-java + ${micronaut.version} + + + io.micronaut + micronaut-validation + ${micronaut.version} + + + + + + + + + + diff --git a/flexible/java-25/micronaut-helloworld/src/main/appengine/app.yaml b/flexible/java-25/micronaut-helloworld/src/main/appengine/app.yaml new file mode 100644 index 00000000000..db82585bc79 --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/src/main/appengine/app.yaml @@ -0,0 +1,27 @@ +# Copyright 2023 Google LLC +# +# 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. +# [START gae_flex_java25_yaml] +runtime: java +env: flex +service: helloworld-java25-flex +runtime_config: + operating_system: ubuntu24 + runtime_version: 25 +handlers: +- url: /.* + script: this field is required, but ignored + +manual_scaling: + instances: 1 +# [END gae_flex_java25_yaml] diff --git a/flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/Application.java b/flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/Application.java new file mode 100644 index 00000000000..e99fbde8f39 --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/Application.java @@ -0,0 +1,26 @@ +/* + * Copyright 2023 Google LLC + * + * 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 com.example.appengine; + +import io.micronaut.runtime.Micronaut; + +public class Application { + + public static void main(String[] args) { + Micronaut.run(Application.class); + } +} diff --git a/flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/HelloController.java b/flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/HelloController.java new file mode 100644 index 00000000000..ac32f9ab102 --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/src/main/java/com/example/appengine/HelloController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 Google LLC + * + * 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 com.example.appengine; + +import io.micronaut.http.MediaType; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Produces; + +@Controller("/") +public class HelloController { + @Get("/") + @Produces(MediaType.TEXT_PLAIN) + public String index() { + return "Hello World!"; + } +} diff --git a/flexible/java-25/micronaut-helloworld/src/main/resources/application.yml b/flexible/java-25/micronaut-helloworld/src/main/resources/application.yml new file mode 100644 index 00000000000..854340b8361 --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/src/main/resources/application.yml @@ -0,0 +1,17 @@ +# Copyright 2023 Google LLC +# +# 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. + +micronaut: + application: + name: micronaut diff --git a/flexible/java-25/micronaut-helloworld/src/main/resources/logback.xml b/flexible/java-25/micronaut-helloworld/src/main/resources/logback.xml new file mode 100644 index 00000000000..4f0363b57df --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/src/main/resources/logback.xml @@ -0,0 +1,28 @@ + + + + + + true + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + diff --git a/flexible/java-25/micronaut-helloworld/src/test/java/com/example/appengine/HelloControllerTest.java b/flexible/java-25/micronaut-helloworld/src/test/java/com/example/appengine/HelloControllerTest.java new file mode 100644 index 00000000000..44571ee72cb --- /dev/null +++ b/flexible/java-25/micronaut-helloworld/src/test/java/com/example/appengine/HelloControllerTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 Google LLC + * + * 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 com.example.appengine; + +import static org.junit.Assert.assertEquals; + +import io.micronaut.context.ApplicationContext; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.client.HttpClient; +import io.micronaut.runtime.server.EmbeddedServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class HelloControllerTest { + private static EmbeddedServer server; + private static HttpClient client; + + @BeforeClass + public static void setupServer() { + + server = ApplicationContext.run(EmbeddedServer.class); + + client = server.getApplicationContext().createBean(HttpClient.class, server.getURL()); + } + + @AfterClass + public static void stopServer() { + if (client != null) { + client.stop(); + } + if (server != null) { + server.stop(); + } + } + + @Test + public void testHelloWorldResponse() { + String response = client.toBlocking().retrieve(HttpRequest.GET("/")); + assertEquals("Hello World!", response); + } +} diff --git a/flexible/java-25/websocket-jetty/README.md b/flexible/java-25/websocket-jetty/README.md new file mode 100644 index 00000000000..8a3ff4e0f2f --- /dev/null +++ b/flexible/java-25/websocket-jetty/README.md @@ -0,0 +1,54 @@ +# App Engine Flexible Environment - Web Socket Example + +This sample demonstrates how to use +[Websockets](https://tools.ietf.org/html/rfc6455) on [Google App Engine Flexible +Environment](https://cloud.google.com/appengine/docs/flexible/java/) using Java. +The sample uses the [native Jetty WebSocket Server +API](http://www.eclipse.org/jetty/documentation/9.4.x/jetty-websocket-server-api.html) +to create a server-side socket and the [native Jetty WebSocket Client +API](http://www.eclipse.org/jetty/documentation/9.4.x/jetty-websocket-client-api.html). + +## Sample application workflow + +1. The sample application creates a server socket using the endpoint `/echo`. +1. The homepage (`/`) provides a form to submit a text message to the server +socket. This creates a client-side socket and sends the message to the server. +1. The server on receiving the message, echoes the message back to the client. +1. The message received by the client is stored in an in-memory cache and is + viewable on the homepage. + +The sample also provides a Javascript +[client](src/main/webapp/js_client.jsp)(`/js_client.jsp`) that you can use to +test against the Websocket server. + +## Setup + +- [Install](https://cloud.google.com/sdk/) and initialize GCloud SDK. This will + + ```sh + gcloud init + ``` + +- If this is your first time creating an app engine application + + ```sh + gcloud appengine create + ``` + +## Deploy + +The sample application is packaged as a war, and hence will be automatically run +using the [Java 8/Jetty 9 with Servlet 3.1 +Runtime](https://cloud.google.com/appengine/docs/flexible/java/dev-jetty9). + +```sh +mvn clean package appengine:deploy +``` + +You can then direct your browser to `https://YOUR_PROJECT_ID.appspot.com/` + +To test the Javascript client, access +`https://YOUR_PROJECT_ID.appspot.com/js_client.jsp` + +Note: This application constructs a Web Socket URL using `getWebSocketAddress` +in the [SendServlet Class](src/main/java/com/example/flexible/websocket/jettynative/SendServlet.java). The application assumes the latest version of the service. diff --git a/flexible/java-25/websocket-jetty/pom.xml b/flexible/java-25/websocket-jetty/pom.xml new file mode 100644 index 00000000000..e216f50b057 --- /dev/null +++ b/flexible/java-25/websocket-jetty/pom.xml @@ -0,0 +1,208 @@ + + + 4.0.0 + + org.eclipse.jetty.demo + native-jetty-websocket-example + 1.0-SNAPSHOT + jar + + + + com.google.cloud.samples + shared-configuration + 1.2.2 + + + + 17 + 17 + false + 9.4.57.v20241219 + 2.7.18 + + + + + + com.google.cloud + libraries-bom + 26.32.0 + pom + import + + + + + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-webapp + ${jetty.version} + jar + + + org.eclipse.jetty + jetty-util + ${jetty.version} + + + org.eclipse.jetty + jetty-annotations + ${jetty.version} + + + + org.eclipse.jetty + apache-jsp + ${jetty.version} + nolog + + + javax.servlet + javax.servlet-api + 4.0.1 + jar + provided + + + + org.eclipse.jetty.websocket + websocket-client + ${jetty.version} + provided + + + org.eclipse.jetty.websocket + websocket-server + ${jetty.version} + provided + + + org.eclipse.jetty.websocket + websocket-servlet + ${jetty.version} + provided + + + com.google.guava + guava + + + org.slf4j + slf4j-simple + 2.0.12 + + + junit + junit + 4.13.2 + test + + + + + + + ${basedir}/src/main/webapp + false + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + + org.apache.maven.plugins + maven-war-plugin + 3.4.0 + + + + com.google.cloud.tools + appengine-maven-plugin + 2.8.0 + + GCLOUD_CONFIG + GCLOUD_CONFIG + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.1 + + + + java + + + + + com.example.flexible.websocket.jettynative.Main + + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty.version} + + jar + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + true + com.example.flexible.websocket.jettynative.Main + + + + jar-with-dependencies + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + diff --git a/flexible/java-25/websocket-jetty/src/main/appengine/app.yaml b/flexible/java-25/websocket-jetty/src/main/appengine/app.yaml new file mode 100644 index 00000000000..b31b02a557e --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/appengine/app.yaml @@ -0,0 +1,33 @@ +# Copyright 2024 Google LLC +# +# 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. + +runtime: java +env: flex +runtime_config: + operating_system: ubuntu22 + runtime_version: 17 +manual_scaling: + instances: 1 +handlers: +- url: /.* + script: this field is required, but ignored + + + +# For applications which can take advantage of session affinity +# (where the load balancer will attempt to route multiple connections from +# the same user to the same App Engine instance), uncomment the folowing: + +# network: +# session_affinity: true diff --git a/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ClientSocket.java b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ClientSocket.java new file mode 100644 index 00000000000..84360e4a904 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ClientSocket.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Google LLC + * + * 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 com.example.flexible.websocket.jettynative; + +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.logging.Logger; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; +import org.eclipse.jetty.websocket.api.annotations.WebSocket; + +/** + * Basic Echo Client Socket. + */ +@WebSocket(maxTextMessageSize = 64 * 1024) +public class ClientSocket { + private Logger logger = Logger.getLogger(ClientSocket.class.getName()); + private Session session; + // stores the messages in-memory. + // Note : this is currently an in-memory store for demonstration, + // not recommended for production use-cases. + private static Collection messages = new ConcurrentLinkedDeque<>(); + + @OnWebSocketClose + public void onClose(int statusCode, String reason) { + logger.fine("Connection closed: " + statusCode + ":" + reason); + this.session = null; + } + + @OnWebSocketConnect + public void onConnect(Session session) { + this.session = session; + } + + @OnWebSocketMessage + public void onMessage(String msg) { + logger.fine("Message Received : " + msg); + messages.add(msg); + } + + // Retrieve all received messages. + public static Collection getReceivedMessages() { + return Collections.unmodifiableCollection(messages); + } +} diff --git a/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/EchoServlet.java b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/EchoServlet.java new file mode 100644 index 00000000000..32358f14268 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/EchoServlet.java @@ -0,0 +1,44 @@ +/* + * Copyright 2024 Google LLC + * + * 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 com.example.flexible.websocket.jettynative; + +import javax.servlet.annotation.WebServlet; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; +import org.eclipse.jetty.websocket.servlet.WebSocketCreator; +import org.eclipse.jetty.websocket.servlet.WebSocketServlet; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; + +/* + * Server-side WebSocket upgraded on /echo servlet. + */ +@SuppressWarnings("serial") +@WebServlet( + name = "Echo WebSocket Servlet", + urlPatterns = {"/echo"}) +public class EchoServlet extends WebSocketServlet implements WebSocketCreator { + @Override + public void configure(WebSocketServletFactory factory) { + factory.setCreator(this); + } + + @Override + public Object createWebSocket( + ServletUpgradeRequest servletUpgradeRequest, ServletUpgradeResponse servletUpgradeResponse) { + return new ServerSocket(); + } +} diff --git a/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java new file mode 100644 index 00000000000..43212718164 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java @@ -0,0 +1,149 @@ +/* + * Copyright 2024 Google LLC + * + * 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 com.example.flexible.websocket.jettynative; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import org.apache.tomcat.util.scan.StandardJarScanFilter; +import org.apache.tomcat.util.scan.StandardJarScanner; +import org.eclipse.jetty.annotations.AnnotationConfiguration; +import org.eclipse.jetty.apache.jsp.JettyJasperInitializer; +import org.eclipse.jetty.jsp.JettyJspServlet; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.component.AbstractLifeCycle; +import org.eclipse.jetty.webapp.Configuration; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.WebInfConfiguration; + +/** + * Starts up the server, including a DefaultServlet that handles static files, and any servlet + * classes annotated with the @WebServlet annotation. + */ +public class Main { + + public static void main(String[] args) throws Exception { + + // Create a server that listens on port 8080. + Server server = new Server(8080); + WebAppContext webAppContext = new WebAppContext(); + server.setHandler(webAppContext); + + // Load static content from inside the jar file. + URL webAppDir = Main.class.getClassLoader().getResource("WEB-INF/"); + System.out.println(webAppDir); + webAppContext.setResourceBase(webAppDir.toURI().toString()); + + // Enable annotations so the server sees classes annotated with @WebServlet. + webAppContext.setConfigurations( + new Configuration[] { + new AnnotationConfiguration(), new WebInfConfiguration(), + }); + + webAppContext.setAttribute( + "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", + ".*/target/classes/|.*\\.jar"); + enableEmbeddedJspSupport(webAppContext); + + ServletHolder holderAltMapping = new ServletHolder(); + holderAltMapping.setName("index.jsp"); + holderAltMapping.setForcedPath("/index.jsp"); + webAppContext.addServlet(holderAltMapping, "/"); + + // Start the server! 🚀 + server.start(); + System.out.println("Server started!"); + + // Keep the main thread alive while the server is running. + server.join(); + } + + private static void enableEmbeddedJspSupport(ServletContextHandler servletContextHandler) + throws IOException { + // Establish Scratch directory for the servlet context (used by JSP compilation) + File tempDir = new File(System.getProperty("java.io.tmpdir")); + File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp"); + + if (!scratchDir.exists()) { + if (!scratchDir.mkdirs()) { + throw new IOException("Unable to create scratch directory: " + scratchDir); + } + } + servletContextHandler.setAttribute("javax.servlet.context.tempdir", scratchDir); + + // Set Classloader of Context to be sane (needed for JSTL) + // JSP requires a non-System classloader, this simply wraps the + // embedded System classloader in a way that makes it suitable + // for JSP to use + ClassLoader jspClassLoader = new URLClassLoader(new URL[0], Main.class.getClassLoader()); + servletContextHandler.setClassLoader(jspClassLoader); + + // Manually call JettyJasperInitializer on context startup + servletContextHandler.addBean(new JspStarter(servletContextHandler)); + + // Create / Register JSP Servlet (must be named "jsp" per spec) + ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class); + holderJsp.setInitOrder(0); + holderJsp.setInitParameter("logVerbosityLevel", "DEBUG"); + holderJsp.setInitParameter("fork", "false"); + holderJsp.setInitParameter("xpoweredBy", "false"); + holderJsp.setInitParameter("compilerTargetVM", "1.8"); + holderJsp.setInitParameter("compilerSourceVM", "1.8"); + holderJsp.setInitParameter("keepgenerated", "true"); + servletContextHandler.addServlet(holderJsp, "*.jsp"); + } + + /** + * JspStarter for embedded ServletContextHandlers + * + *

This is added as a bean that is a jetty LifeCycle on the ServletContextHandler. This bean's + * doStart method will be called as the ServletContextHandler starts, and will call the + * ServletContainerInitializer for the jsp engine. + */ + public static class JspStarter extends AbstractLifeCycle + implements ServletContextHandler.ServletContainerInitializerCaller { + JettyJasperInitializer sci; + ServletContextHandler context; + + public JspStarter(ServletContextHandler context) { + this.sci = new JettyJasperInitializer(); + this.context = context; + String skip = "apache-*,ecj-*,jetty-*,asm-*,javax.servlet-*" + + "javax.annotation-*,taglibs-standard-spec-*,*.jar"; + StandardJarScanner jarScanner = new StandardJarScanner(); + StandardJarScanFilter jarScanFilter = new StandardJarScanFilter(); + jarScanFilter.setTldSkip(skip); + jarScanner.setJarScanFilter(jarScanFilter); + this.context.setAttribute("org.apache.tomcat.JarScanner", jarScanner); + } + + @Override + protected void doStart() throws Exception { + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(context.getClassLoader()); + try { + sci.onStartup(null, context.getServletContext()); + super.doStart(); + } finally { + Thread.currentThread().setContextClassLoader(old); + } + } + } +} diff --git a/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/SendServlet.java b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/SendServlet.java new file mode 100644 index 00000000000..0feab349ac2 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/SendServlet.java @@ -0,0 +1,143 @@ +/* + * Copyright 2024 Google LLC + * + * 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 com.example.flexible.websocket.jettynative; + +import com.google.common.base.Preconditions; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.Future; +import java.util.logging.Logger; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.client.WebSocketClient; + +@WebServlet("/send") +/** Servlet that sends the message sent over POST to over a websocket connection. */ +public class SendServlet extends HttpServlet { + + private Logger logger = Logger.getLogger(SendServlet.class.getName()); + + private static final String ENDPOINT = "/echo"; + private static final String WEBSOCKET_PROTOCOL_PREFIX = "ws://"; + private static final String WEBSOCKET_HTTPS_PROTOCOL_PREFIX = "wss://"; + private static final String APPENGINE_HOST_SUFFIX = ".appspot.com"; + + // GAE_INSTANCE environment is used to detect App Engine Flexible Environment + private static final String GAE_INSTANCE_VAR = "GAE_INSTANCE"; + // GOOGLE_CLOUD_PROJECT environment variable is set to the GCP project ID on App Engine Flexible. + private static final String GOOGLE_CLOUD_PROJECT_ENV_VAR = "GOOGLE_CLOUD_PROJECT"; + // GAE_SERVICE environment variable is set to the GCP service name. + private static final String GAE_SERVICE_ENV_VAR = "GAE_SERVICE"; + + private final HttpClient httpClient; + private final WebSocketClient webSocketClient; + private final ClientSocket clientSocket; + + public SendServlet() { + this.httpClient = createHttpClient(); + this.webSocketClient = createWebSocketClient(); + this.clientSocket = new ClientSocket(); + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + String message = request.getParameter("message"); + try { + sendMessageOverWebSocket(message); + response.sendRedirect("/"); + } catch (Exception e) { + logger.severe("Error sending message over socket: " + e.getMessage()); + e.printStackTrace(response.getWriter()); + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500); + } + } + + private HttpClient createHttpClient() { + HttpClient httpClient; + if (System.getenv(GAE_INSTANCE_VAR) != null) { + // If on HTTPS, create client with SSL Context + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + httpClient = new HttpClient(sslContextFactory); + } else { + // local testing on HTTP + httpClient = new HttpClient(); + } + return httpClient; + } + + private WebSocketClient createWebSocketClient() { + return new WebSocketClient(this.httpClient); + } + + private void sendMessageOverWebSocket(String message) throws Exception { + if (!httpClient.isRunning()) { + try { + httpClient.start(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + if (!webSocketClient.isRunning()) { + try { + webSocketClient.start(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + ClientUpgradeRequest request = new ClientUpgradeRequest(); + // Attempt connection + Future future = + webSocketClient.connect(clientSocket, new URI(getWebSocketAddress()), request); + // Wait for Connect + Session session = future.get(); + // Send a message + session.getRemote().sendString(message); + // Close session + session.close(); + } + + /** + * Returns the host:port/echo address a client needs to use to communicate with the server. On App + * engine Flex environments, result will be in the form wss://project-id.appspot.com/echo + */ + public static String getWebSocketAddress() { + // Use ws://127.0.0.1:8080/echo when testing locally + String webSocketHost = "127.0.0.1:8080"; + String webSocketProtocolPrefix = WEBSOCKET_PROTOCOL_PREFIX; + + // On App Engine flexible environment, use wss://project-id.appspot.com/echo + if (System.getenv(GAE_INSTANCE_VAR) != null) { + String projectId = System.getenv(GOOGLE_CLOUD_PROJECT_ENV_VAR); + if (projectId != null) { + String serviceName = System.getenv(GAE_SERVICE_ENV_VAR); + webSocketHost = serviceName + "-dot-" + projectId + APPENGINE_HOST_SUFFIX; + } + Preconditions.checkNotNull(webSocketHost); + // Use wss:// instead of ws:// protocol when connecting over https + webSocketProtocolPrefix = WEBSOCKET_HTTPS_PROTOCOL_PREFIX; + } + return webSocketProtocolPrefix + webSocketHost + ENDPOINT; + } +} diff --git a/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ServerSocket.java b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ServerSocket.java new file mode 100644 index 00000000000..07cfafe0f3e --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/ServerSocket.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Google LLC + * + * 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 com.example.flexible.websocket.jettynative; + +import java.io.IOException; +import java.util.logging.Logger; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; +import org.eclipse.jetty.websocket.api.annotations.WebSocket; + +/* + * Server-side WebSocket : echoes received message back to client. + */ +@WebSocket(maxTextMessageSize = 64 * 1024) +public class ServerSocket { + private Logger logger = Logger.getLogger(SendServlet.class.getName()); + private Session session; + + @OnWebSocketConnect + public void onWebSocketConnect(Session session) { + this.session = session; + logger.fine("Socket Connected: " + session); + } + + @OnWebSocketMessage + public void onWebSocketText(String message) { + logger.fine("Received message: " + message); + try { + // echo message back to client + this.session.getRemote().sendString(message); + } catch (IOException e) { + logger.severe("Error echoing message: " + e.getMessage()); + } + } + + @OnWebSocketClose + public void onWebSocketClose(int statusCode, String reason) { + logger.fine("Socket Closed: [" + statusCode + "] " + reason); + } + + @OnWebSocketError + public void onWebSocketError(Throwable cause) { + logger.severe("Websocket error : " + cause.getMessage()); + } +} diff --git a/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/index.jsp b/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/index.jsp new file mode 100644 index 00000000000..8730c529584 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/index.jsp @@ -0,0 +1,33 @@ + + +<%@ page import="com.example.flexible.websocket.jettynative.ClientSocket" %> + + + + + Send a message + +

Publish a message

+
+ + + +
+

Last received messages

+ <%= ClientSocket.getReceivedMessages() %> + + diff --git a/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/jetty-web.xml b/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/jetty-web.xml new file mode 100644 index 00000000000..475971850a9 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/jetty-web.xml @@ -0,0 +1,24 @@ + + + + + + true + + -org.eclipse.jetty. + + diff --git a/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/js_client.jsp b/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/js_client.jsp new file mode 100644 index 00000000000..ef9d7051928 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/main/webapp/WEB-INF/js_client.jsp @@ -0,0 +1,85 @@ + + + +<%@ page import="com.example.flexible.websocket.jettynative.SendServlet" %> + + Google App Engine Flexible Environment - WebSocket Echo + + + +

Echo demo

+
+ + +
+ +
+

Messages:

+
    +
    + +
    +

    Status:

    +
      +
      + + + + diff --git a/flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/ClientSocketTest.java b/flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/ClientSocketTest.java new file mode 100644 index 00000000000..6b8636852ef --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/ClientSocketTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Google LLC + * + * 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 com.example.flexible.websocket.jettynative; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +public class ClientSocketTest { + ClientSocket socket; + + @Before + public void setUp() { + socket = new ClientSocket(); + } + + @Test + public void testOnMessage() { + assertEquals(ClientSocket.getReceivedMessages().size(), 0); + socket.onMessage("test"); + assertEquals(ClientSocket.getReceivedMessages().size(), 1); + } +} diff --git a/flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/SendServletTest.java b/flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/SendServletTest.java new file mode 100644 index 00000000000..37916cb6a37 --- /dev/null +++ b/flexible/java-25/websocket-jetty/src/test/java/com/example/flexible/websocket/jettynative/SendServletTest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Google LLC + * + * 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 com.example.flexible.websocket.jettynative; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class SendServletTest { + @Test + public void testGetWebSocketAddress() { + assertTrue(SendServlet.getWebSocketAddress().contains("/echo")); + } +} From da44fe886f794c5a3012b155aa321215442f2a4c Mon Sep 17 00:00:00 2001 From: Abhinand Sundararajan Date: Mon, 3 Nov 2025 17:46:50 +0530 Subject: [PATCH 2/3] Addressing auto-review comments and taking comments from previous PR https://github.com/GoogleCloudPlatform/java-docs-samples/pull/10193 --- appengine-java21/ee8/analytics/pom.xml | 6 +++--- flexible/java-25/websocket-jetty/README.md | 4 +--- flexible/java-25/websocket-jetty/pom.xml | 4 ++-- .../com/example/flexible/websocket/jettynative/Main.java | 4 ++-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/appengine-java21/ee8/analytics/pom.xml b/appengine-java21/ee8/analytics/pom.xml index 441a48e6887..889c0059c81 100644 --- a/appengine-java21/ee8/analytics/pom.xml +++ b/appengine-java21/ee8/analytics/pom.xml @@ -32,9 +32,9 @@ - 1.8 - 1.8 - 2.0.23 + 25 + 25 + 3.0.1 diff --git a/flexible/java-25/websocket-jetty/README.md b/flexible/java-25/websocket-jetty/README.md index 8a3ff4e0f2f..cbc8394e054 100644 --- a/flexible/java-25/websocket-jetty/README.md +++ b/flexible/java-25/websocket-jetty/README.md @@ -37,9 +37,7 @@ test against the Websocket server. ## Deploy -The sample application is packaged as a war, and hence will be automatically run -using the [Java 8/Jetty 9 with Servlet 3.1 -Runtime](https://cloud.google.com/appengine/docs/flexible/java/dev-jetty9). +The sample application is packaged as a jar and runs on the Java 25 runtime. ```sh mvn clean package appengine:deploy diff --git a/flexible/java-25/websocket-jetty/pom.xml b/flexible/java-25/websocket-jetty/pom.xml index e216f50b057..72fff67201b 100644 --- a/flexible/java-25/websocket-jetty/pom.xml +++ b/flexible/java-25/websocket-jetty/pom.xml @@ -34,8 +34,8 @@ - 17 - 17 + 25 + 25 false 9.4.57.v20241219 2.7.18 diff --git a/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java index 43212718164..357deac5ce0 100644 --- a/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java +++ b/flexible/java-25/websocket-jetty/src/main/java/com/example/flexible/websocket/jettynative/Main.java @@ -104,8 +104,8 @@ private static void enableEmbeddedJspSupport(ServletContextHandler servletContex holderJsp.setInitParameter("logVerbosityLevel", "DEBUG"); holderJsp.setInitParameter("fork", "false"); holderJsp.setInitParameter("xpoweredBy", "false"); - holderJsp.setInitParameter("compilerTargetVM", "1.8"); - holderJsp.setInitParameter("compilerSourceVM", "1.8"); + holderJsp.setInitParameter("compilerTargetVM", "25"); + holderJsp.setInitParameter("compilerSourceVM", "25"); holderJsp.setInitParameter("keepgenerated", "true"); servletContextHandler.addServlet(holderJsp, "*.jsp"); } From dd50bfe3acc6e82df388aee04aca500474a4433f Mon Sep 17 00:00:00 2001 From: Abhinand Sundararajan Date: Tue, 4 Nov 2025 00:17:47 +0530 Subject: [PATCH 3/3] Changing Java25 Micronaut and Websocket Flex samples to bytecode java21 since java25 is not yet stable in Micronaut and Websocket Jetty ecosystem. --- flexible/java-25/micronaut-helloworld/pom.xml | 55 ++++++++++++------ flexible/java-25/websocket-jetty/pom.xml | 56 +++++++++++++++---- 2 files changed, 83 insertions(+), 28 deletions(-) diff --git a/flexible/java-25/micronaut-helloworld/pom.xml b/flexible/java-25/micronaut-helloworld/pom.xml index 8657747cee9..80463b16868 100644 --- a/flexible/java-25/micronaut-helloworld/pom.xml +++ b/flexible/java-25/micronaut-helloworld/pom.xml @@ -34,6 +34,7 @@ 21 21 3.10.3 + ${argLine} @@ -86,7 +87,7 @@ com.google.cloud.tools appengine-maven-plugin - 2.8.0 + 2.8.3 GCLOUD_CONFIG micronaut-helloworld @@ -95,7 +96,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.1 + 3.5.2 package @@ -116,7 +117,7 @@ org.codehaus.mojo exec-maven-plugin - 3.1.1 + 3.2.0 java @@ -131,7 +132,7 @@ maven-surefire-plugin - 3.2.5 + 3.2.2 @@ -166,23 +167,41 @@ -parameters - - - io.micronaut - micronaut-inject-java - ${micronaut.version} - - - io.micronaut - micronaut-validation - ${micronaut.version} - - - + + + io.micronaut + micronaut-inject-java + ${micronaut.version} + + + io.micronaut + micronaut-validation + ${micronaut.version} + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.12 + + + + prepare-agent + + + + report + prepare-package + + report + - + \ No newline at end of file diff --git a/flexible/java-25/websocket-jetty/pom.xml b/flexible/java-25/websocket-jetty/pom.xml index 72fff67201b..e8da5205900 100644 --- a/flexible/java-25/websocket-jetty/pom.xml +++ b/flexible/java-25/websocket-jetty/pom.xml @@ -34,8 +34,8 @@ - 25 - 25 + 21 + 21 false 9.4.57.v20241219 2.7.18 @@ -63,7 +63,6 @@ org.eclipse.jetty jetty-webapp ${jetty.version} - jar org.eclipse.jetty @@ -75,20 +74,34 @@ jetty-annotations ${jetty.version} - org.eclipse.jetty apache-jsp ${jetty.version} - nolog - javax.servlet - javax.servlet-api - 4.0.1 + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + 2.0.0 + + + org.glassfish.web + jakarta.servlet.jsp.jstl + 2.0.0 + + + jakarta.servlet + jakarta.servlet-api + 5.0.0 jar provided + + jakarta.websocket + jakarta.websocket-api + 2.1.1 + provided + org.eclipse.jetty.websocket @@ -100,7 +113,6 @@ org.eclipse.jetty.websocket websocket-server ${jetty.version} - provided org.eclipse.jetty.websocket @@ -108,6 +120,11 @@ ${jetty.version} provided + + org.eclipse.jetty.websocket + websocket-servlet + ${jetty.version} + com.google.guava guava @@ -145,7 +162,7 @@ com.google.cloud.tools appengine-maven-plugin - 2.8.0 + 2.8.3 GCLOUD_CONFIG GCLOUD_CONFIG @@ -203,6 +220,25 @@ + + org.jacoco + jacoco-maven-plugin + 0.8.14 + + + + prepare-agent + + + + report + prepare-package + + report + + + +