// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/internal/SpanWrapper.java
// public class SpanWrapper {
// 
//     public static final String PROPERTY_NAME = SpanWrapper.class.getName() + ".activeSpanWrapper";
// 
//     private Scope scope;
//     private Span span;
//     private AtomicBoolean finished = new AtomicBoolean();
// 
//     public SpanWrapper(Span span, Scope scope) {
//         this.span = span;
//         this.scope = scope;
// 
//     }
// 
//     public Span get() {
//         return span;
//     }
// 
//     public Scope getScope() {
//         return scope;
//     }
// 
//     public void finish() {
//         if (finished.compareAndSet(false, true)) {
//             span.finish();
//         }
//     }
// 
//     public boolean isFinished() {
//         return finished.get();
//     }
// }


import io.opentracing.References;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.contrib.jaxrs2.internal.SpanWrapper;
import io.opentracing.noop.NoopSpan;
import io.opentracing.tag.Tags;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.InterceptorContext;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
    public void aroundWriteTo(WriterInterceptorContext context)
        throws IOException, WebApplicationException {
        Span span = buildSpan(context, "serialize");
        try (Scope scope = tracer.activateSpan(span)) {
            decorateWrite(context, span);
            context.proceed();
        } catch (Exception e) {
            Tags.ERROR.set(span, true);
            throw e;
        } finally {
            span.finish();
        }
    }

    /**
     * Client requests :
     * <ul>
     * <li>Serialization of request body happens between the tracing filter invocation so we can use child_of.</li>
     * <li>Deserialization happens after the request is processed by the client filter therefore we can use follows_from only.</li>
     * </ul>
     * Server requests :
     * <ul>
     * <li>Deserialization happens between the span in the server filter is started and finished so we can use child_of.</li>
     * <li>Serialization of response entity happens after the server span if finished so we can use only follows_from.</li>
     * </ul>
     * @param context Used to retrieve the current span wrapper created by the jax-rs request filter.
     * @param operationName "serialize" or "deserialize" depending on the context
     * @return a noop span is no span context is registered in the context. Otherwise a new span related to the current on retrieved from the context.
     */
    private Span buildSpan(InterceptorContext context, String operationName) {
// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/internal/SpanWrapper.java
// public class SpanWrapper {
// 
//     public static final String PROPERTY_NAME = SpanWrapper.class.getName() + ".activeSpanWrapper";
// 
//     private Scope scope;
//     private Span span;
//     private AtomicBoolean finished = new AtomicBoolean();
// 
//     public SpanWrapper(Span span, Scope scope) {
//         this.span = span;
//         this.scope = scope;
// 
//     }
// 
//     public Span get() {
//         return span;
//     }
// 
//     public Scope getScope() {
//         return scope;
//     }
// 
//     public void finish() {
//         if (finished.compareAndSet(false, true)) {
//             span.finish();
//         }
//     }
// 
//     public boolean isFinished() {
//         return finished.get();
//     }
// }


// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/serialization/TracingInterceptor.java
import io.opentracing.References;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.contrib.jaxrs2.internal.SpanWrapper;
import io.opentracing.noop.NoopSpan;
import io.opentracing.tag.Tags;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.InterceptorContext;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;

    public void aroundWriteTo(WriterInterceptorContext context)
        throws IOException, WebApplicationException {
        Span span = buildSpan(context, "serialize");
        try (Scope scope = tracer.activateSpan(span)) {
            decorateWrite(context, span);
            context.proceed();
        } catch (Exception e) {
            Tags.ERROR.set(span, true);
            throw e;
        } finally {
            span.finish();
        }
    }

    /**
     * Client requests :
     * <ul>
     * <li>Serialization of request body happens between the tracing filter invocation so we can use child_of.</li>
     * <li>Deserialization happens after the request is processed by the client filter therefore we can use follows_from only.</li>
     * </ul>
     * Server requests :
     * <ul>
     * <li>Deserialization happens between the span in the server filter is started and finished so we can use child_of.</li>
     * <li>Serialization of response entity happens after the server span if finished so we can use only follows_from.</li>
     * </ul>
     * @param context Used to retrieve the current span wrapper created by the jax-rs request filter.
     * @param operationName "serialize" or "deserialize" depending on the context
     * @return a noop span is no span context is registered in the context. Otherwise a new span related to the current on retrieved from the context.
     */
    private Span buildSpan(InterceptorContext context, String operationName) {
        final SpanWrapper spanWrapper = findSpan(context);