From 69458ac0baaa50c44bd8627ef7ef67d5f45c2770 Mon Sep 17 00:00:00 2001 From: "James R. Perkins" Date: Wed, 12 Apr 2023 12:36:23 -0700 Subject: [PATCH] Add a new tracing resource and frontend page to execute requests and display the header data. Signed-off-by: James R. Perkins --- tracing-example/README.adoc | 14 +- tracing-example/pom.xml | 67 +++++--- .../examples/tracing/TraceMethodResource.java | 57 +++++++ .../resteasy/examples/tracing/TracingApp.java | 2 +- .../src/main/webapp/WEB-INF/beans.xml | 20 +++ tracing-example/src/main/webapp/index.html | 113 ++++++++++++++ .../src/main/webapp/resources/main.js | 146 ++++++++++++++++++ .../examples/tracing/TracingTest.java | 6 +- 8 files changed, 398 insertions(+), 27 deletions(-) create mode 100644 tracing-example/src/main/java/dev/resteasy/examples/tracing/TraceMethodResource.java create mode 100644 tracing-example/src/main/webapp/WEB-INF/beans.xml create mode 100644 tracing-example/src/main/webapp/index.html create mode 100644 tracing-example/src/main/webapp/resources/main.js diff --git a/tracing-example/README.adoc b/tracing-example/README.adoc index ff175240..2f642527 100644 --- a/tracing-example/README.adoc +++ b/tracing-example/README.adoc @@ -1,4 +1,4 @@ -== Usage += RESTEasy Tracing Example This is a demonstration of the resteasy tracing feature. @@ -9,11 +9,14 @@ To run the example, you can simply run it with WildFly: $ mvn wildfly:run ---- +== Usage + After server started, we can access the server and get the tracing info: +=== Command Line [source,bash] ---- -$ curl -i http://localhost:8080/tracing-example/level +$ curl -i http://localhost:8080/tracing-example/trace/level ---- And here is the sample output: @@ -34,4 +37,9 @@ X-RESTEasy-Tracing-189: org.jboss.resteasy.plugins.server.servlet.Servlet3AsyncH X-RESTEasy-Tracing-190: org.jboss.resteasy.plugins.server.servlet.Servlet3AsyncHttpRequest@5c54713c MBW [ ---- / 90378.04 ms | ---- %] Find MBW for type=[java.lang.String] genericType=[java.lang.String] mediaType=[[jakarta.ws.rs.core.MediaType @45b9c1ef]] annotations=[@jakarta.ws.rs.GET(), @jakarta.ws.rs.Path(value="/level")] ---- -Above is the basic usage of the sample. You should also see output on the console WildFly is running in as well. \ No newline at end of file +Above is the basic usage of the sample. You should also see output on the console WildFly is running in as well. + +=== Web + +Navigate to http://localhost:8080/tracing-example. From there you should see a web page which can be used to execute +HTTP requests through a client returning the tracing headers. \ No newline at end of file diff --git a/tracing-example/pom.xml b/tracing-example/pom.xml index d008b981..a6b422ad 100644 --- a/tracing-example/pom.xml +++ b/tracing-example/pom.xml @@ -47,16 +47,6 @@ - - - wildfly27 - - 27.0.1.Final - compile - - - - @@ -196,16 +186,47 @@ ${version.wildfly-maven-plugin} ${jboss.home} + ${jboss.home} + + + org.wildfly + wildfly-ee-galleon-pack + ${version.org.wildfly} + + + + true + - provision-test-server + provision-server process-test-classes provision + + + + + + + + + wildfly27 + + 27.0.1.Final + compile + + + + + + org.wildfly.plugins + wildfly-maven-plugin + ${version.wildfly-maven-plugin} - ${jboss.home} + ${jboss.home} @@ -224,13 +245,19 @@ ${version.org.jboss.resteasy} - - true - - - - - - + + + provision-server + process-test-classes + + provision + + + + + + + + diff --git a/tracing-example/src/main/java/dev/resteasy/examples/tracing/TraceMethodResource.java b/tracing-example/src/main/java/dev/resteasy/examples/tracing/TraceMethodResource.java new file mode 100644 index 00000000..0240ba9b --- /dev/null +++ b/tracing-example/src/main/java/dev/resteasy/examples/tracing/TraceMethodResource.java @@ -0,0 +1,57 @@ +/* + * JBoss, Home of Professional Open Source. + * + * Copyright 2023 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 dev.resteasy.examples.tracing; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +/** + * @author James R. Perkins + */ +@Path("/headers") +@RequestScoped +@Consumes(MediaType.TEXT_PLAIN) +@Produces(MediaType.TEXT_PLAIN) +public class TraceMethodResource { + + @GET + @Path("get") + public String get() { + return "GET trace"; + } + + @POST + @Path("post") + public String post(final String value) { + return String.format("POST trace: %s", value); + } + + @PUT + @Path("put") + public String put(final String value) { + return String.format("PUT trace: %s", value); + } +} diff --git a/tracing-example/src/main/java/dev/resteasy/examples/tracing/TracingApp.java b/tracing-example/src/main/java/dev/resteasy/examples/tracing/TracingApp.java index 485a4b76..cfcedc73 100644 --- a/tracing-example/src/main/java/dev/resteasy/examples/tracing/TracingApp.java +++ b/tracing-example/src/main/java/dev/resteasy/examples/tracing/TracingApp.java @@ -3,6 +3,6 @@ import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; -@ApplicationPath("/") +@ApplicationPath("/trace") public class TracingApp extends Application { } diff --git a/tracing-example/src/main/webapp/WEB-INF/beans.xml b/tracing-example/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000..ac9e52bb --- /dev/null +++ b/tracing-example/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,20 @@ + + + \ No newline at end of file diff --git a/tracing-example/src/main/webapp/index.html b/tracing-example/src/main/webapp/index.html new file mode 100644 index 00000000..d95db8ed --- /dev/null +++ b/tracing-example/src/main/webapp/index.html @@ -0,0 +1,113 @@ + + + + + + + + Contacts + + + + + + + +
+
+
+ +
+
+
+ Choose the HTTP method to invoke: +
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+
+ HTTP Method: +
+
+ Invoked: +
+
+ Response: +
+
+ + + + + + + + + + +
Header NameHeader Value
+
+ + + + + \ No newline at end of file diff --git a/tracing-example/src/main/webapp/resources/main.js b/tracing-example/src/main/webapp/resources/main.js new file mode 100644 index 00000000..23effe26 --- /dev/null +++ b/tracing-example/src/main/webapp/resources/main.js @@ -0,0 +1,146 @@ +/* + * JBoss, Home of Professional Open Source. + * + * Copyright 2023 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. + */ + +(() => { + "use strict"; + + window.addEventListener("load", () => { + // Enable tooltips + const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); + [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl, { + trigger: "hover", + delay: 500 + })); + // Add the functions to the buttons + const submitButton = document.querySelector("#submit"); + submitButton.addEventListener("click", () => { + const radioButtons = document.querySelectorAll("input[name='httpMethod']"); + let httpMethod; + for (const radioButton of radioButtons) { + if (radioButton.checked) { + httpMethod = radioButton.value; + break; + } + } + loadTable(httpMethod); + }); + const clearButton = document.querySelector("#clear"); + clearButton.addEventListener("click", () => { + // Clear the elements we want to be reset + const link = document.querySelector("#url"); + clearElement(link); + link.classList.remove("placeholder", "col-5", "bg-secondary"); + clearElement(document.querySelector("#sentHttpMethod")); + clearElement(document.querySelector("#response")); + clearElement(document.querySelector("#output")); + }); + }); + + function loadTable(httpMethod) { + const link = document.querySelector("#url"); + document.querySelector("#sentHttpMethod").textContent = httpMethod.toUpperCase(); + clearElement(link); + link.classList.add("placeholder", "col-5", "bg-secondary"); + + // Get the table body for the output + const tbody = document.querySelector("#output"); + // Clear the table + clearElement(tbody); + // Add a temporary row to the table to indicate we are loading + const trTemp = tbody.insertRow(); + const col1Temp = trTemp.insertCell(); + const spinnerDiv = document.createElement("div"); + spinnerDiv.classList.add("spinner-border"); + spinnerDiv.setAttribute("role", "status"); + const spinner = document.createElement("span"); + spinner.classList.add("visually-hidden"); + spinner.textContent = "Loading..."; + spinnerDiv.append(spinner); + col1Temp.append(spinnerDiv); + trTemp.insertCell(); + + const url = "trace/headers/" + httpMethod; + // Create potential data + let config = {}; + if (httpMethod === "post" || httpMethod === "put") { + config = { + method: httpMethod.toUpperCase(), + body: `${httpMethod} data` + }; + } + fetch(url, config) + .then((r) => { + // Create a link to the resource we just invoked + const a = document.createElement("a"); + a.setAttribute("href", r.url); + a.setAttribute("target", "_"); + a.textContent = r.url; + link.classList.remove("placeholder", "col-5", "bg-secondary"); + link.append(a); + r.text().then((text) => { + clearElement(tbody); + document.querySelector("#response").textContent = text; + // Add a table entry for each header value + const headers = r.headers; + for (let header of headers.entries()) { + const tr = tbody.insertRow(); + const name = tr.insertCell(); + name.textContent = header[0]; + const value = tr.insertCell(); + value.textContent = header[1]; + } + }); + }).catch(err => { + error("Request has failed: " + err); + }); + } + + /** + * Clears the children of the element. + * @param e the element to clear + */ + function clearElement(e) { + while (e.firstChild) { + e.removeChild(e.firstChild); + } + } + + function success(message) { + showAlert(message); + } + + function error(message) { + showAlert(message, "danger"); + } + + function showAlert(message, type = "success", autoHide = "true") { + const alertPlaceholder = document.querySelector("#liveAlertPlaceholder"); + const alert = document.querySelector("#alert").content.cloneNode(true).querySelector("div.toast"); + alert.setAttribute("data-bs-autohide", autoHide); + alert.classList.add("text-bg-" + type); + const body = alert.querySelector(".toast-body"); + body.textContent = message; + alert.addEventListener("hidden.bs.toast", () => { + alertPlaceholder.removeChild(alert); + }); + const toast = new bootstrap.Toast(alert); + toast.show(); + alertPlaceholder.append(alert); + } +})() \ No newline at end of file diff --git a/tracing-example/src/test/java/dev/resteasy/examples/tracing/TracingTest.java b/tracing-example/src/test/java/dev/resteasy/examples/tracing/TracingTest.java index da244f8d..83091676 100644 --- a/tracing-example/src/test/java/dev/resteasy/examples/tracing/TracingTest.java +++ b/tracing-example/src/test/java/dev/resteasy/examples/tracing/TracingTest.java @@ -56,13 +56,13 @@ public static WebArchive deployment() { @Test public void basicTest() { try (Client client = ClientBuilder.newClient()) { - WebTarget target = client.target(uriBuilder().path("type")); + WebTarget target = client.target(uriBuilder().path("trace/type")); assertEquals(ResteasyContextParameters.RESTEASY_TRACING_TYPE_ALL, target.request().get(String.class)); - target = client.target(uriBuilder().path("level")); + target = client.target(uriBuilder().path("trace/level")); assertEquals(ResteasyContextParameters.RESTEASY_TRACING_LEVEL_VERBOSE, target.request().get(String.class)); - target = client.target(uriBuilder().path("logger")); + target = client.target(uriBuilder().path("trace/logger")); assertEquals(RESTEasyTracingLogger.class.getName(), target.request().get(String.class)); } }