Skip to content

Commit a799207

Browse files
authored
Add support for struts 2.3 with tests (#244)
* adding struts2.3 framework support tests * spotless apply for build * polishing, review comments * refining code
1 parent 0dd2977 commit a799207

File tree

6 files changed

+264
-0
lines changed

6 files changed

+264
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ List of supported frameworks with additional capabilities:
2525
| [Spark Web Framework](https://github.com/perwendel/spark) | 2.3+ |
2626
| [Spring Webflux](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/package-summary.html) | 5.0+ |
2727
| [Vert.x](https://vertx.io) | 3.0+ |
28+
| [Struts](https://struts.apache.org/) | 2.3+ |
2829

2930
### Adding custom filter implementation
3031

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
plugins {
2+
`java-library`
3+
id("io.opentelemetry.instrumentation.auto-instrumentation")
4+
muzzle
5+
}
6+
7+
muzzle {
8+
pass {
9+
group = "org.apache.struts"
10+
module = "struts2-core"
11+
versions = "[2.3.1,)"
12+
}
13+
}
14+
15+
val versions: Map<String, String> by extra
16+
17+
dependencies {
18+
testImplementation(project(":instrumentation:servlet:servlet-rw"))
19+
testImplementation(project(":instrumentation:servlet:servlet-3.0-no-wrapping"))
20+
testImplementation(project(":testing-common")) {
21+
exclude(group ="org.eclipse.jetty", module= "jetty-server")
22+
}
23+
testImplementation("io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-servlet-3.0:${versions["opentelemetry_java_agent"]}")
24+
testImplementation("org.apache.struts:struts2-core:2.3.1")
25+
testImplementation("org.apache.struts:struts2-json-plugin:2.3.1")
26+
testImplementation("org.apache.struts:struts2-convention-plugin:2.3.1")
27+
testImplementation("org.eclipse.jetty:jetty-server:8.0.0.v20110901")
28+
testImplementation("org.eclipse.jetty:jetty-servlet:8.0.0.v20110901")
29+
testImplementation("javax.servlet:javax.servlet-api:3.0.1")
30+
testImplementation("javax.servlet:jsp-api:2.0")
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright The Hypertrace Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.opentelemetry.javaagent.instrumentation.hypertrace.struts;
18+
19+
import com.opensymphony.xwork2.ActionSupport;
20+
import org.apache.struts2.convention.annotation.ParentPackage;
21+
import org.apache.struts2.convention.annotation.Result;
22+
23+
@Result(type = "json")
24+
@ParentPackage("json-default")
25+
public class Struts2Action extends ActionSupport {
26+
27+
private String jsonString = "{'balance':1000.21,'is_vip':true,'num':100,'name':'foo'}";
28+
29+
public String body() {
30+
return "body";
31+
}
32+
33+
public String headers() {
34+
return "headers";
35+
}
36+
37+
public String getJsonString() {
38+
return jsonString;
39+
}
40+
41+
public void setJsonString(String jsonString) {
42+
this.jsonString = jsonString;
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright The Hypertrace Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.opentelemetry.javaagent.instrumentation.hypertrace.struts;
18+
19+
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
21+
import io.opentelemetry.sdk.trace.data.SpanData;
22+
import java.io.IOException;
23+
import java.util.EnumSet;
24+
import java.util.List;
25+
import java.util.concurrent.TimeoutException;
26+
import javax.servlet.DispatcherType;
27+
import okhttp3.MediaType;
28+
import okhttp3.Request;
29+
import okhttp3.RequestBody;
30+
import okhttp3.Response;
31+
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
32+
import org.eclipse.jetty.server.Server;
33+
import org.eclipse.jetty.servlet.DefaultServlet;
34+
import org.eclipse.jetty.servlet.ServletContextHandler;
35+
import org.eclipse.jetty.util.resource.FileResource;
36+
import org.hypertrace.agent.core.instrumentation.HypertraceSemanticAttributes;
37+
import org.hypertrace.agent.testing.AbstractInstrumenterTest;
38+
import org.junit.jupiter.api.AfterAll;
39+
import org.junit.jupiter.api.Assertions;
40+
import org.junit.jupiter.api.BeforeAll;
41+
import org.junit.jupiter.api.Test;
42+
43+
public class StrutsInstrumentationTest extends AbstractInstrumenterTest {
44+
45+
private static final String REQUEST_BODY = "hello";
46+
private static final String REQUEST_HEADER = "requestheader";
47+
private static final String REQUEST_HEADER_VALUE = "requestvalue";
48+
private static final String RESPONSE_HEADER = "headerName";
49+
private static final String RESPONSE_HEADER_VALUE = "headerValue";
50+
51+
private static Server server = new Server(0);
52+
private static int serverPort;
53+
54+
@BeforeAll
55+
public static void startServer() throws Exception {
56+
ServletContextHandler handler = new ServletContextHandler();
57+
FileResource resource = new FileResource(StrutsInstrumentationTest.class.getResource("/"));
58+
handler.setContextPath("/context");
59+
handler.setBaseResource(resource);
60+
handler.addServlet(DefaultServlet.class, "/");
61+
handler.addFilter(
62+
StrutsPrepareAndExecuteFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
63+
server.setHandler(handler);
64+
server.start();
65+
serverPort = server.getConnectors()[0].getLocalPort();
66+
}
67+
68+
@AfterAll
69+
public static void stopServer() throws Exception {
70+
server.stop();
71+
}
72+
73+
@Test
74+
public void postUrlEncoded() throws IOException, TimeoutException, InterruptedException {
75+
Request request =
76+
new Request.Builder()
77+
.url(String.format("http://localhost:%d/context/body", serverPort))
78+
.post(
79+
RequestBody.create(
80+
REQUEST_BODY, MediaType.get("application/x-www-form-urlencoded")))
81+
.build();
82+
try (Response response = httpClient.newCall(request).execute()) {
83+
assertEquals(200, response.code());
84+
}
85+
86+
TEST_WRITER.waitForTraces(1);
87+
List<List<SpanData>> traces = TEST_WRITER.getTraces();
88+
assertEquals(1, traces.size());
89+
List<SpanData> spans = traces.get(0);
90+
assertEquals(1, spans.size());
91+
SpanData spanData = spans.get(0);
92+
assertEquals(
93+
"\"" + new Struts2Action().getJsonString() + "\"",
94+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_RESPONSE_BODY));
95+
assertEquals(
96+
REQUEST_BODY, spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_REQUEST_BODY));
97+
}
98+
99+
@Test
100+
public void getHeaders() throws IOException, TimeoutException, InterruptedException {
101+
Request request =
102+
new Request.Builder()
103+
.url(String.format("http://localhost:%d/context/headers", serverPort))
104+
.get()
105+
.header(REQUEST_HEADER, REQUEST_HEADER_VALUE)
106+
.build();
107+
try (Response response = httpClient.newCall(request).execute()) {
108+
assertEquals(200, response.code());
109+
}
110+
111+
TEST_WRITER.waitForTraces(1);
112+
List<List<SpanData>> traces = TEST_WRITER.getTraces();
113+
assertEquals(1, traces.size());
114+
List<SpanData> spans = traces.get(0);
115+
assertEquals(1, spans.size());
116+
SpanData spanData = spans.get(0);
117+
assertEquals(
118+
RESPONSE_HEADER_VALUE,
119+
spanData
120+
.getAttributes()
121+
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_HEADER)));
122+
assertEquals(
123+
REQUEST_HEADER_VALUE,
124+
spanData
125+
.getAttributes()
126+
.get(HypertraceSemanticAttributes.httpRequestHeader(REQUEST_HEADER)));
127+
}
128+
129+
@Test
130+
public void block() throws IOException, TimeoutException, InterruptedException {
131+
Request request =
132+
new Request.Builder()
133+
.url(String.format("http://localhost:%d/context/body", serverPort))
134+
.get()
135+
.header("mockblock", "true")
136+
.build();
137+
try (Response response = httpClient.newCall(request).execute()) {
138+
Assertions.assertEquals(403, response.code());
139+
}
140+
141+
TEST_WRITER.waitForTraces(1);
142+
List<List<SpanData>> traces = TEST_WRITER.getTraces();
143+
Assertions.assertEquals(1, traces.size());
144+
List<SpanData> spans = traces.get(0);
145+
Assertions.assertEquals(1, spans.size());
146+
SpanData spanData = spans.get(0);
147+
Assertions.assertNull(
148+
spanData
149+
.getAttributes()
150+
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_HEADER)));
151+
Assertions.assertNull(
152+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_REQUEST_BODY));
153+
Assertions.assertNull(
154+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_RESPONSE_BODY));
155+
}
156+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE struts PUBLIC
3+
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
4+
"http://struts.apache.org/dtds/struts-2.3.dtd">
5+
6+
<struts>
7+
8+
<constant name="struts.enable.SlashesInActionNames" value="true"/>
9+
<constant name="struts.patternMatcher" value="namedVariable"/>
10+
11+
<package name="basic-struts2" extends="struts-default">
12+
<global-results>
13+
<result name="headers" type="httpheader" >
14+
<param name="headers.headerName">headerValue</param>
15+
</result>
16+
</global-results>
17+
<action name="headers" class="io.opentelemetry.javaagent.instrumentation.hypertrace.struts.Struts2Action" method="headers"/>
18+
</package>
19+
20+
<package name="json-struts2" extends="json-default">
21+
<action name="body" class="io.opentelemetry.javaagent.instrumentation.hypertrace.struts.Struts2Action" method="body">
22+
<result name="body" type="json">
23+
<param name="noCache">true</param>
24+
<param name="excludeNullProperties">true</param>
25+
<param name="root">jsonString</param>
26+
</result>
27+
</action>
28+
</package>
29+
30+
</struts>

settings.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,5 @@ include("instrumentation:servlet:servlet-3.0-no-wrapping")
5959
findProject(":instrumentation:servlet:servlet-3.0-no-wrapping")?.name = "servlet-3.0-no-wrapping"
6060
include("instrumentation:servlet:servlet-rw")
6161
findProject(":instrumentation:servlet:servlet-rw")?.name = "servlet-rw"
62+
include("instrumentation:struts-2.3")
63+
findProject(":instrumentation:struts-2.3")?.name = "struts-2.3"

0 commit comments

Comments
 (0)