Skip to content

Commit dcd0d9f

Browse files
authored
Add Jakarta EE9 Equivalents of all libraries (#962)
Add Jakarta EE9 Equivalents of all libraries This is the second attempt at this. This version however is significantly simpler than the previous version since we had already converted all of the tests to a simpler undertow only implementation, removing the Dropwizard dependency which inadvertently bumped all of our dependencies past compatible versions. Tests have been consciously dropped in the non-jakarta versions as the dependencies get messed up with those. Similarly, revapi was dropped from the non-jakarta versions because of a quirk in how that plugin works. It's not providing value here anyways though.
1 parent 4de7f67 commit dcd0d9f

File tree

20 files changed

+510
-122
lines changed

20 files changed

+510
-122
lines changed

settings.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ include 'tracing-api'
55
include 'tracing-benchmarks'
66
include 'tracing-demos'
77
include 'tracing-jaxrs'
8+
include 'tracing-jaxrs-jakarta'
89
include 'tracing-jersey'
10+
include 'tracing-jersey-jakarta'
911
include 'tracing-okhttp3'
1012
include 'tracing-servlet'
13+
include 'tracing-servlet-jakarta'
1114
include 'tracing-test-utils'
1215
include 'tracing-undertow'
1316

14-
include 'tracing-undertow-testing'
17+
include 'tracing-undertow-jakarta-testing'

tracing-jaxrs-jakarta/build.gradle

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
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+
apply plugin: 'org.inferred.processors'
18+
19+
apply plugin: 'com.palantir.external-publish-jar'
20+
apply plugin: 'com.palantir.revapi'
21+
22+
dependencies {
23+
api project(":tracing")
24+
api "jakarta.ws.rs:jakarta.ws.rs-api"
25+
26+
testImplementation "ch.qos.logback:logback-classic"
27+
testImplementation "org.junit.jupiter:junit-jupiter"
28+
testImplementation "org.assertj:assertj-core"
29+
testImplementation "org.jmock:jmock"
30+
testImplementation "org.mockito:mockito-core"
31+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
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 com.palantir.tracing.jaxrs;
18+
19+
import com.palantir.tracing.CloseableSpan;
20+
import com.palantir.tracing.Detached;
21+
import com.palantir.tracing.DetachedSpan;
22+
import com.palantir.tracing.Tracers;
23+
import jakarta.ws.rs.WebApplicationException;
24+
import jakarta.ws.rs.core.StreamingOutput;
25+
import java.io.IOException;
26+
import java.io.OutputStream;
27+
import java.util.concurrent.Callable;
28+
29+
public final class JaxRsTracers {
30+
31+
private JaxRsTracers() {}
32+
33+
/** Like {@link Tracers#wrap(Callable)}, but for StreamingOutputs. */
34+
public static StreamingOutput wrap(StreamingOutput delegate) {
35+
return new TracingAwareStreamingOutput(delegate);
36+
}
37+
38+
private static class TracingAwareStreamingOutput implements StreamingOutput {
39+
40+
private final StreamingOutput delegate;
41+
private final Detached detached;
42+
43+
TracingAwareStreamingOutput(StreamingOutput delegate) {
44+
this.delegate = delegate;
45+
this.detached = DetachedSpan.detach();
46+
}
47+
48+
@Override
49+
public void write(OutputStream output) throws IOException, WebApplicationException {
50+
try (CloseableSpan ignored = detached.childSpan("streaming-output")) {
51+
delegate.write(output);
52+
}
53+
}
54+
}
55+
}

tracing-jaxrs/src/test/java/com/palantir/tracing/jaxrs/JaxRsTracersTest.java renamed to tracing-jaxrs-jakarta/src/test/java/com/palantir/tracing/jaxrs/JaxRsTracersTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
import com.palantir.tracing.AlwaysSampler;
2222
import com.palantir.tracing.Tracer;
23+
import jakarta.ws.rs.core.StreamingOutput;
2324
import java.io.ByteArrayOutputStream;
24-
import javax.ws.rs.core.StreamingOutput;
25-
import org.junit.Test;
25+
import org.junit.jupiter.api.Test;
2626

2727
public final class JaxRsTracersTest {
2828

tracing-jaxrs/build.gradle

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,12 @@
1717
apply plugin: 'org.inferred.processors'
1818

1919
apply plugin: 'com.palantir.external-publish-jar'
20-
apply plugin: 'com.palantir.revapi'
20+
21+
versionsLock {
22+
disableJavaPluginDefaults()
23+
}
2124

2225
dependencies {
2326
api project(":tracing")
24-
api "jakarta.ws.rs:jakarta.ws.rs-api"
25-
26-
testImplementation "ch.qos.logback:logback-classic"
27-
testImplementation "junit:junit"
28-
testImplementation "org.assertj:assertj-core"
29-
testImplementation "org.jmock:jmock"
30-
testImplementation "org.mockito:mockito-core"
27+
api "javax.ws.rs:javax.ws.rs-api"
3128
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
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+
apply plugin: 'com.palantir.external-publish-jar'
18+
apply plugin: 'com.palantir.revapi'
19+
20+
dependencies {
21+
api "org.glassfish.jersey.core:jersey-server"
22+
api project(":tracing")
23+
24+
implementation 'com.google.guava:guava'
25+
implementation 'jakarta.ws.rs:jakarta.ws.rs-api'
26+
implementation project(':tracing-api')
27+
28+
testImplementation project(":tracing-undertow-jakarta-testing")
29+
testImplementation 'org.glassfish.jersey.inject:jersey-hk2'
30+
testImplementation "org.junit.jupiter:junit-jupiter"
31+
testImplementation "org.assertj:assertj-core"
32+
testImplementation "org.hamcrest:hamcrest-all"
33+
testImplementation "org.mockito:mockito-core"
34+
testImplementation "org.mockito:mockito-junit-jupiter"
35+
36+
// needed for MDC tests
37+
testRuntimeOnly "org.apache.logging.log4j:log4j-slf4j-impl"
38+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
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 com.palantir.tracing.jersey;
18+
19+
import com.google.common.annotations.VisibleForTesting;
20+
import com.google.common.base.Strings;
21+
import com.palantir.tracing.Observability;
22+
import com.palantir.tracing.TagTranslator;
23+
import com.palantir.tracing.TraceMetadata;
24+
import com.palantir.tracing.Tracer;
25+
import com.palantir.tracing.Tracers;
26+
import com.palantir.tracing.api.SpanType;
27+
import com.palantir.tracing.api.TraceHttpHeaders;
28+
import com.palantir.tracing.api.TraceTags;
29+
import jakarta.annotation.Priority;
30+
import jakarta.ws.rs.container.ContainerRequestContext;
31+
import jakarta.ws.rs.container.ContainerRequestFilter;
32+
import jakarta.ws.rs.container.ContainerResponseContext;
33+
import jakarta.ws.rs.container.ContainerResponseFilter;
34+
import jakarta.ws.rs.core.Context;
35+
import jakarta.ws.rs.core.HttpHeaders;
36+
import jakarta.ws.rs.core.MultivaluedMap;
37+
import jakarta.ws.rs.ext.Provider;
38+
import java.io.IOException;
39+
import java.util.Optional;
40+
import java.util.function.BiConsumer;
41+
import java.util.function.Consumer;
42+
import org.glassfish.jersey.server.ExtendedUriInfo;
43+
import org.glassfish.jersey.server.model.Resource;
44+
45+
// Default is `Priorities.USER` == 5000. This filter needs to execute earlier to ensure traces are ready to use.
46+
@Priority(500)
47+
@Provider
48+
public final class TraceEnrichingFilter implements ContainerRequestFilter, ContainerResponseFilter {
49+
public static final TraceEnrichingFilter INSTANCE = new TraceEnrichingFilter();
50+
51+
/**
52+
* This is the name of the trace id property we set on {@link ContainerRequestContext}.
53+
*/
54+
public static final String TRACE_ID_PROPERTY_NAME = "com.palantir.tracing.traceId";
55+
56+
public static final String REQUEST_ID_PROPERTY_NAME = "com.palantir.tracing.requestId";
57+
58+
public static final String SAMPLED_PROPERTY_NAME = "com.palantir.tracing.sampled";
59+
60+
@VisibleForTesting
61+
static final String FETCH_USER_AGENT_HEADER = "Fetch-User-Agent";
62+
63+
@Context
64+
@SuppressWarnings("NullAway") // instantiated using by Jersey using reflection
65+
private ExtendedUriInfo uriInfo;
66+
67+
// Handles incoming request
68+
@Override
69+
public void filter(ContainerRequestContext requestContext) throws IOException {
70+
String path = getPathTemplate();
71+
72+
String operation = "Jersey: " + requestContext.getMethod() + " " + path;
73+
// The following strings are all nullable
74+
String traceId = requestContext.getHeaderString(TraceHttpHeaders.TRACE_ID);
75+
String spanId = requestContext.getHeaderString(TraceHttpHeaders.SPAN_ID);
76+
Optional<String> forUserAgent = getForUserAgent(requestContext);
77+
78+
// Set up thread-local span that inherits state from HTTP headers
79+
if (Strings.isNullOrEmpty(traceId)) {
80+
// HTTP request did not indicate a trace; initialize trace state and create a span.
81+
Tracer.initTraceWithSpan(
82+
getObservabilityFromHeader(requestContext),
83+
Tracers.randomId(),
84+
forUserAgent,
85+
operation,
86+
SpanType.SERVER_INCOMING);
87+
} else if (spanId == null) {
88+
Tracer.initTraceWithSpan(
89+
getObservabilityFromHeader(requestContext),
90+
traceId,
91+
forUserAgent,
92+
operation,
93+
SpanType.SERVER_INCOMING);
94+
} else {
95+
// caller's span is this span's parent.
96+
Tracer.initTraceWithSpan(
97+
getObservabilityFromHeader(requestContext),
98+
traceId,
99+
forUserAgent,
100+
operation,
101+
spanId,
102+
SpanType.SERVER_INCOMING);
103+
}
104+
105+
// Give asynchronous downstream handlers access to the trace id
106+
requestContext.setProperty(TRACE_ID_PROPERTY_NAME, Tracer.getTraceId());
107+
requestContext.setProperty(SAMPLED_PROPERTY_NAME, Tracer.isTraceObservable());
108+
Tracer.maybeGetTraceMetadata()
109+
.flatMap(TraceMetadata::getRequestId)
110+
.ifPresent(requestId -> requestContext.setProperty(REQUEST_ID_PROPERTY_NAME, requestId));
111+
}
112+
113+
// Handles outgoing response
114+
@Override
115+
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
116+
throws IOException {
117+
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
118+
if (Tracer.hasTraceId()) {
119+
String traceId = Tracer.getTraceId();
120+
Tracer.fastCompleteSpan(FunctionalTagTranslator.INSTANCE, sink -> {
121+
sink.accept(TraceTags.HTTP_STATUS_CODE, Integer.toString(responseContext.getStatus()));
122+
sink.accept(TraceTags.HTTP_URL_PATH_TEMPLATE, getPathTemplate());
123+
sink.accept(TraceTags.HTTP_METHOD, requestContext.getMethod());
124+
Object requestId = requestContext.getProperty(REQUEST_ID_PROPERTY_NAME);
125+
if (requestId instanceof String) {
126+
sink.accept(TraceTags.HTTP_REQUEST_ID, (String) requestId);
127+
}
128+
});
129+
headers.putSingle(TraceHttpHeaders.TRACE_ID, traceId);
130+
} else {
131+
// When the filter is called twice (e.g. an exception is thrown in a streaming call),
132+
// the current trace will be empty. To allow clients to still get the trace ID corresponding to
133+
// the failure, we retrieve it from the requestContext.
134+
Optional.ofNullable(requestContext.getProperty(TRACE_ID_PROPERTY_NAME))
135+
.ifPresent(s -> headers.putSingle(TraceHttpHeaders.TRACE_ID, s));
136+
}
137+
}
138+
139+
// Force sample iff the context contains a "1" X-B3-Sampled header, force not sample if the header contains another
140+
// non-empty value, or undecided if there is no such header or the header is empty.
141+
private static Observability getObservabilityFromHeader(ContainerRequestContext context) {
142+
String header = context.getHeaderString(TraceHttpHeaders.IS_SAMPLED);
143+
if (Strings.isNullOrEmpty(header)) {
144+
return Observability.UNDECIDED;
145+
} else {
146+
return "1".equals(header) ? Observability.SAMPLE : Observability.DO_NOT_SAMPLE;
147+
}
148+
}
149+
150+
private static Optional<String> getForUserAgent(ContainerRequestContext context) {
151+
String forUserAgent = context.getHeaderString(TraceHttpHeaders.FOR_USER_AGENT);
152+
if (forUserAgent != null) {
153+
return Optional.of(forUserAgent);
154+
}
155+
String fetchUserAgent = context.getHeaderString(FETCH_USER_AGENT_HEADER);
156+
if (fetchUserAgent != null) {
157+
return Optional.of(fetchUserAgent);
158+
}
159+
return Optional.ofNullable(context.getHeaderString(HttpHeaders.USER_AGENT));
160+
}
161+
162+
private String getPathTemplate() {
163+
return Optional.ofNullable(uriInfo)
164+
.map(ExtendedUriInfo::getMatchedModelResource)
165+
.map(Resource::getPath)
166+
.orElse("(unknown)");
167+
}
168+
169+
private enum FunctionalTagTranslator implements TagTranslator<Consumer<BiConsumer<String, String>>> {
170+
INSTANCE;
171+
172+
@Override
173+
public <T> void translate(TagAdapter<T> adapter, T target, Consumer<BiConsumer<String, String>> data) {
174+
data.accept((key, value) -> adapter.tag(target, key, value));
175+
}
176+
}
177+
}

tracing-jersey/src/test/java/com/palantir/tracing/jersey/TraceEnrichingFilterTest.java renamed to tracing-jersey-jakarta/src/test/java/com/palantir/tracing/jersey/TraceEnrichingFilterTest.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@
3535
import com.palantir.tracing.api.TraceHttpHeaders;
3636
import com.palantir.tracing.api.TraceTags;
3737
import com.palantir.undertest.UndertowServerExtension;
38-
import javax.ws.rs.Consumes;
39-
import javax.ws.rs.GET;
40-
import javax.ws.rs.POST;
41-
import javax.ws.rs.Path;
42-
import javax.ws.rs.Produces;
43-
import javax.ws.rs.container.ContainerRequestContext;
44-
import javax.ws.rs.core.HttpHeaders;
45-
import javax.ws.rs.core.MediaType;
46-
import javax.ws.rs.core.StreamingOutput;
38+
import jakarta.ws.rs.Consumes;
39+
import jakarta.ws.rs.GET;
40+
import jakarta.ws.rs.POST;
41+
import jakarta.ws.rs.Path;
42+
import jakarta.ws.rs.Produces;
43+
import jakarta.ws.rs.container.ContainerRequestContext;
44+
import jakarta.ws.rs.core.HttpHeaders;
45+
import jakarta.ws.rs.core.MediaType;
46+
import jakarta.ws.rs.core.StreamingOutput;
4747
import org.apache.hc.client5.http.classic.methods.HttpGet;
4848
import org.apache.hc.client5.http.classic.methods.HttpPost;
4949
import org.apache.hc.core5.http.ContentType;

0 commit comments

Comments
 (0)