Skip to content

Commit

Permalink
JAX-RS ApplicationPath annotation (#2824)
Browse files Browse the repository at this point in the history
  • Loading branch information
laurit committed Apr 21, 2021
1 parent c4071c1 commit a3c0b44
Show file tree
Hide file tree
Showing 52 changed files with 845 additions and 89 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ext {
skipPublish = true
}
apply from: "$rootDir/gradle/java.gradle"

// add repo for org.gradle:gradle-tooling-api which org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-gradle-depchain depends on
repositories {
maven { url 'https://repo.gradle.org/gradle/libs-releases' }
}

dependencies {
compileOnly "javax:javaee-api:7.0"

api project(':testing-common')
implementation deps.opentelemetryApi

def arquillianVersion = '1.4.0.Final'
implementation "org.jboss.arquillian.junit:arquillian-junit-container:${arquillianVersion}"
implementation "org.jboss.arquillian.protocol:arquillian-protocol-servlet:${arquillianVersion}"
implementation 'org.jboss.arquillian.spock:arquillian-spock-container:1.0.0.CR1'
api "org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-gradle-depchain:3.1.3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

import static io.opentelemetry.api.trace.SpanKind.SERVER

import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.utils.OkHttpUtils
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jboss.arquillian.container.test.api.Deployment
import org.jboss.arquillian.container.test.api.RunAsClient
import org.jboss.arquillian.spock.ArquillianSputnik
import org.jboss.arquillian.test.api.ArquillianResource
import org.jboss.shrinkwrap.api.ShrinkWrap
import org.jboss.shrinkwrap.api.asset.EmptyAsset
import org.jboss.shrinkwrap.api.spec.WebArchive
import org.junit.runner.RunWith
import spock.lang.Unroll
import test.CdiRestResource
import test.EjbRestResource
import test.RestApplication

@RunWith(ArquillianSputnik)
@RunAsClient
abstract class ArquillianRestTest extends AgentInstrumentationSpecification {

static OkHttpClient client = OkHttpUtils.client()

@ArquillianResource
static URI url

@Deployment
static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive)
.addClass(RestApplication)
.addClass(CdiRestResource)
.addClass(EjbRestResource)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
}

def getContextRoot() {
return url.getPath()
}

@Unroll
def "test #path"() {
when:
Request request = new Request.Builder().url(HttpUrl.get(url.resolve(path))).build()
Response response = client.newCall(request).execute()

then:
response.withCloseable {
assert response.code() == 200
assert response.body().string() == "hello"
true
}

and:
assertTraces(1) {
trace(0, 2) {
span(0) {
name getContextRoot() + path
kind SERVER
hasNoParent()
}
span(1) {
name className + ".hello"
childOf span(0)
}
}
}

where:
path | className
"rest-app/cdiHello" | "CdiRestResource"
"rest-app/ejbHello" | "EjbRestResource"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/")
@ApplicationPath("/rest-app/")
public class RestApplication extends Application {

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">

<defaultProtocol type="Servlet 3.0" />

<container qualifier="wildfly-embedded" default="true">
<configuration>
<property name="jbossHome">build/server/wildfly-18.0.0.Final</property>
<property name="modulePath">build/server/wildfly-18.0.0.Final/modules</property>
</configuration>
</container>
</arquillian>
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
import io.opentelemetry.javaagent.instrumentation.api.ClassHierarchyIterable;
import io.opentelemetry.javaagent.instrumentation.api.jaxrs.JaxrsContextPath;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -66,6 +67,7 @@ public void updateSpanNames(
// empty when method and class don't have a jax-rs path annotation, this can happen when
// creating an "abort" span, see RequestContextHelper.
if (!pathBasedSpanName.isEmpty()) {
pathBasedSpanName = JaxrsContextPath.prepend(context, pathBasedSpanName);
pathBasedSpanName = ServletContextPath.prepend(context, pathBasedSpanName);
}
if (serverSpan == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@ muzzle {
group = "org.apache.cxf"
module = "cxf-rt-frontend-jaxrs"
versions = "[3.2,)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
pass {
group = "org.apache.tomee"
module = "openejb-cxf-rs"
// earlier versions of tomee use cxf older than 3.2
versions = "(8,)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
}

dependencies {
compileOnly group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0'
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
library group: 'org.apache.cxf', name: 'cxf-rt-frontend-jaxrs', version: '3.2.0'

implementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:javaagent')
Expand All @@ -21,6 +30,7 @@ dependencies {

testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-testing')
testImplementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3'
testImplementation group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '9.4.6.v20170531'

testLibrary group: 'org.apache.cxf', name: 'cxf-rt-transports-http-jetty', version: '3.2.0'
testLibrary group: 'org.apache.cxf', name: 'cxf-rt-ws-policy', version: '3.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0;

import static java.util.Arrays.asList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Collections;
import java.util.List;

@AutoService(InstrumentationModule.class)
Expand All @@ -19,6 +20,9 @@ public CxfInstrumentationModule() {

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return Collections.singletonList(new CxfRequestContextInstrumentation());
return asList(
new CxfRequestContextInstrumentation(),
new CxfServletControllerInstrumentation(),
new CxfRsHttpListenerInstrumentation());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0;

import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.jaxrs.JaxrsContextPath;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

// TomEE specific instrumentation
public class CxfRsHttpListenerInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.apache.openejb.server.cxf.rs.CxfRsHttpListener");
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(named("doInvoke")),
CxfRsHttpListenerInstrumentation.class.getName() + "$InvokeAdvice");
}

public static class InvokeAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.FieldValue("pattern") String pattern, @Advice.Local("otelScope") Scope scope) {
Context context = JaxrsContextPath.init(Java8BytecodeBridge.currentContext(), pattern);
if (context != null) {
scope = context.makeCurrent();
}
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(@Advice.Local("otelScope") Scope scope) {
if (scope != null) {
scope.close();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0;

import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.jaxrs.JaxrsContextPath;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Collections;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

public class CxfServletControllerInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.apache.cxf.transport.servlet.ServletController");
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return Collections.singletonMap(
isMethod()
.and(isPublic())
.and(named("invokeDestination"))
.and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))),
CxfServletControllerInstrumentation.class.getName() + "$InvokeAdvice");
}

public static class InvokeAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.Argument(0) HttpServletRequest httpServletRequest,
@Advice.Local("otelScope") Scope scope) {
Context context =
JaxrsContextPath.init(
Java8BytecodeBridge.currentContext(), httpServletRequest.getServletPath());
if (context != null) {
scope = context.makeCurrent();
}
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(@Advice.Local("otelScope") Scope scope) {
if (scope != null) {
scope.close();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import javax.ws.rs.core.Response
import javax.ws.rs.ext.ExceptionMapper
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean
import org.apache.cxf.endpoint.Server
import test.JaxRsTestApplication

class CxfHttpServerTest extends JaxRsHttpServerTest<Server> {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

class CxfJettyHttpServerTest extends JaxRsJettyHttpServerTest {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" metadata-complete="false"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

<servlet>
<servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>test.JaxRsApplicationPathTestApplication</param-value>
</init-param>
<async-supported>true</async-supported>
</servlet>

<servlet-mapping>
<servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
<url-pattern>/rest-app/*</url-pattern>
</servlet-mapping>
</web-app>
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,29 @@ muzzle {
group = "org.glassfish.jersey.core"
module = "jersey-server"
versions = "[2.0,3.0.0)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
pass {
group = "org.glassfish.jersey.containers"
module = "jersey-container-servlet"
versions = "[2.0,3.0.0)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
}

dependencies {
compileOnly group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0'
compileOnly group: 'org.glassfish.jersey.core', name: 'jersey-server', version: '2.0'
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
library group: 'org.glassfish.jersey.core', name: 'jersey-server', version: '2.0'
library group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.0'

implementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:javaagent')

testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-javax-common:javaagent')

testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-testing')
testImplementation group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '8.0.0.v20110901'

// First version with DropwizardTestSupport:
testLibrary group: 'io.dropwizard', name: 'dropwizard-testing', version: '0.8.0'
Expand Down

0 comments on commit a3c0b44

Please sign in to comment.