package brave.jaxrs2;
import brave.Tracer;
import brave.http.HttpTracing;
import brave.http.ITServletContainer;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher;
import org.jboss.resteasy.plugins.server.servlet.ListenerBootstrap;
import org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap;
import org.jboss.resteasy.spi.ResteasyConfiguration;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.junit.AssumptionViolatedException;
import org.junit.Test;
public class ITTracingFeature_Container extends ITServletContainer {
@Override @Test public void reportsClientAddress() {
throw new AssumptionViolatedException("ContainerRequestContext doesn't include remote address");
}
@Path("")
public static class TestResource { // public for resteasy to inject
final Tracer tracer;
TestResource(HttpTracing httpTracing) {
this.tracer = httpTracing.tracing().tracer();
}
@GET
@Path("foo")
public Response get() {
return Response.status(200).build();
}
@GET
@Path("badrequest")
public Response badrequest() {
return Response.status(400).build();
}
@GET
@Path("child")
public Response child() {
tracer.nextSpan().name("child").start().finish();
return Response.status(200).build();
}
@GET
@Path("async")
public void async(@Suspended AsyncResponse response) throws IOException {
new Thread(() -> response.resume("ok")).start();
}
@GET
@Path("exception")
public Response disconnect() throws IOException {
throw new IOException();
}
@GET
@Path("exceptionAsync")
public void disconnectAsync(@Suspended AsyncResponse response) throws IOException {
new Thread(() -> response.resume(new IOException())).start();
}
}
/**
* {@link ContainerResponseFilter} has no means to handle uncaught exceptions. Unless you provide
* a catch-all exception mapper, requests that result in unhandled exceptions will leak until they
* are eventually flushed.
*/
@Provider
public static class CatchAllExceptions implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception e) {
if (e instanceof WebApplicationException) {
return ((WebApplicationException) e).getResponse();
}
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Internal error")
.type("text/plain")
.build();
}
}
@Override public void init(ServletContextHandler handler) {
// Adds application programmatically as opposed to using web.xml
handler.addServlet(new ServletHolder(new HttpServletDispatcher()), "/*");
handler.addEventListener(new ResteasyBootstrap() {
@Override public void contextInitialized(ServletContextEvent event) {
deployment = new ResteasyDeployment();
deployment.setApplication(new Application(){
@Override public Set<Object> getSingletons() {
return new LinkedHashSet<>(Arrays.asList(
new TestResource(httpTracing),
new CatchAllExceptions(),
new TracingFeature(httpTracing)
));
}
});
ServletContext servletContext = event.getServletContext();
ListenerBootstrap config = new ListenerBootstrap(servletContext);
servletContext.setAttribute(ResteasyDeployment.class.getName(), deployment);
deployment.getDefaultContextObjects().put(ResteasyConfiguration.class, config);
config.createDeployment();
deployment.start();
}
});
}
}