// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/serialization/InterceptorSpanDecorator.java
// public interface InterceptorSpanDecorator {
// 
//     /**
//      * Decorate spans by outgoing object.
//      *
//      * @param context
//      * @param span
//      */
//     void decorateRead(InterceptorContext context, Span span);
// 
//     /**
//      * Decorate spans by outgoing object.
//      *
//      * @param context
//      * @param span
//      */
//     void decorateWrite(InterceptorContext context, Span span);
// 
//     /**
//      * Adds tags: \"media.type\", \"entity.type\"
//      */
//     InterceptorSpanDecorator STANDARD_TAGS = new InterceptorSpanDecorator() {
//         @Override
//         public void decorateRead(InterceptorContext context, Span span) {
//             span.setTag("media.type", context.getMediaType().toString());
//             span.setTag("entity.type", context.getType().getName());
//         }
// 
//         @Override
//         public void decorateWrite(InterceptorContext context, Span span) {
//             decorateRead(context, span);
//         }
//     };
// }
// 
// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/server/OperationNameProvider.java
// class WildcardOperationName implements OperationNameProvider {
//   static class Builder implements OperationNameProvider.Builder {
//     @Override
//     public OperationNameProvider build(Class<?> clazz, Method method) {
//       String classPath = extractPath(clazz);
//       String methodPath = extractPath(method);
//       if (classPath == null || methodPath == null) {
//         for (Class<?> i: clazz.getInterfaces()) {
//           if (classPath == null) {
//             String intfPath = extractPath(i);
//             if (intfPath != null) {
//               classPath = intfPath;
//             }
//           }
//           if (methodPath == null) {
//             for (Method m: i.getMethods()) {
//               if (Objects.equals(m.getName(), method.getName()) && Arrays.deepEquals(m.getParameterTypes(), method.getParameterTypes())) {
//                 methodPath = extractPath(m);
//               }
//             }
//           }
//         }
//       }
//       return new WildcardOperationName(classPath == null ? "" : classPath, methodPath == null ? "" : methodPath);
//     }
//     private static String extractPath(AnnotatedElement element) {
//       Path path = element.getAnnotation(Path.class);
//       if (path != null) {
//         return path.value();
//       }
//       return null;
//     }
//   }
// 
//   private final String path;
// 
//   WildcardOperationName(String clazz, String method) {
//     if (clazz.isEmpty() || clazz.charAt(0) != '/') {
//       clazz = "/" + clazz;
//     }
//     if (clazz.endsWith("/")) {
//       clazz = clazz.substring(0, clazz.length() - 1);
//     }
//     if (method.isEmpty() || method.charAt(0) != '/') {
//       method = "/" + method;
//     }
//     this.path = clazz + method;
//   }
// 
//   @Override
//   public String operationName(ContainerRequestContext requestContext) {
//     return requestContext.getMethod() + ":" + path;
//   }
// 
//   public static Builder newBuilder() {
//     return new Builder();
//   }
// }


import io.opentracing.Tracer;
import io.opentracing.contrib.jaxrs2.serialization.InterceptorSpanDecorator;
import io.opentracing.contrib.jaxrs2.server.OperationNameProvider.WildcardOperationName;
import io.opentracing.util.GlobalTracer;
import org.eclipse.microprofile.opentracing.Traced;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
    protected Traced closestTracedAnnotation(ResourceInfo resourceInfo) {
        Traced tracedAnnotation = resourceInfo.getResourceMethod().getAnnotation(Traced.class);
        if (tracedAnnotation == null) {
            tracedAnnotation = resourceInfo.getResourceClass().getAnnotation(Traced.class);
        }

        return tracedAnnotation;
    }

    protected boolean tracingDisabled(ResourceInfo resourceInfo) {
        Traced traced = closestTracedAnnotation(resourceInfo);
        return traced == null ? !builder.allTraced : !traced.value();
    }

    protected String operationName(ResourceInfo resourceInfo) {
        Traced traced = closestTracedAnnotation(resourceInfo);
        return traced != null && !traced.operationName().isEmpty()  ? traced.operationName() : null;
    }

    /**
     * Builder for creating JAX-RS dynamic feature for tracing server requests.
     *
     * By default span's operation name is HTTP method and span is decorated with
     * {@link ServerSpanDecorator#STANDARD_TAGS} which adds standard tags.
     * If you want to set different span name provide custom span decorator {@link ServerSpanDecorator}.
     */
    public static class Builder {
        private final Tracer tracer;
        private boolean allTraced;
        private List<ServerSpanDecorator> spanDecorators;
// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/serialization/InterceptorSpanDecorator.java
// public interface InterceptorSpanDecorator {
// 
//     /**
//      * Decorate spans by outgoing object.
//      *
//      * @param context
//      * @param span
//      */
//     void decorateRead(InterceptorContext context, Span span);
// 
//     /**
//      * Decorate spans by outgoing object.
//      *
//      * @param context
//      * @param span
//      */
//     void decorateWrite(InterceptorContext context, Span span);
// 
//     /**
//      * Adds tags: \"media.type\", \"entity.type\"
//      */
//     InterceptorSpanDecorator STANDARD_TAGS = new InterceptorSpanDecorator() {
//         @Override
//         public void decorateRead(InterceptorContext context, Span span) {
//             span.setTag("media.type", context.getMediaType().toString());
//             span.setTag("entity.type", context.getType().getName());
//         }
// 
//         @Override
//         public void decorateWrite(InterceptorContext context, Span span) {
//             decorateRead(context, span);
//         }
//     };
// }
// 
// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/server/OperationNameProvider.java
// class WildcardOperationName implements OperationNameProvider {
//   static class Builder implements OperationNameProvider.Builder {
//     @Override
//     public OperationNameProvider build(Class<?> clazz, Method method) {
//       String classPath = extractPath(clazz);
//       String methodPath = extractPath(method);
//       if (classPath == null || methodPath == null) {
//         for (Class<?> i: clazz.getInterfaces()) {
//           if (classPath == null) {
//             String intfPath = extractPath(i);
//             if (intfPath != null) {
//               classPath = intfPath;
//             }
//           }
//           if (methodPath == null) {
//             for (Method m: i.getMethods()) {
//               if (Objects.equals(m.getName(), method.getName()) && Arrays.deepEquals(m.getParameterTypes(), method.getParameterTypes())) {
//                 methodPath = extractPath(m);
//               }
//             }
//           }
//         }
//       }
//       return new WildcardOperationName(classPath == null ? "" : classPath, methodPath == null ? "" : methodPath);
//     }
//     private static String extractPath(AnnotatedElement element) {
//       Path path = element.getAnnotation(Path.class);
//       if (path != null) {
//         return path.value();
//       }
//       return null;
//     }
//   }
// 
//   private final String path;
// 
//   WildcardOperationName(String clazz, String method) {
//     if (clazz.isEmpty() || clazz.charAt(0) != '/') {
//       clazz = "/" + clazz;
//     }
//     if (clazz.endsWith("/")) {
//       clazz = clazz.substring(0, clazz.length() - 1);
//     }
//     if (method.isEmpty() || method.charAt(0) != '/') {
//       method = "/" + method;
//     }
//     this.path = clazz + method;
//   }
// 
//   @Override
//   public String operationName(ContainerRequestContext requestContext) {
//     return requestContext.getMethod() + ":" + path;
//   }
// 
//   public static Builder newBuilder() {
//     return new Builder();
//   }
// }


// Path: opentracing-jaxrs2/src/main/java/io/opentracing/contrib/jaxrs2/server/ServerTracingDynamicFeature.java
import io.opentracing.Tracer;
import io.opentracing.contrib.jaxrs2.serialization.InterceptorSpanDecorator;
import io.opentracing.contrib.jaxrs2.server.OperationNameProvider.WildcardOperationName;
import io.opentracing.util.GlobalTracer;
import org.eclipse.microprofile.opentracing.Traced;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

    protected Traced closestTracedAnnotation(ResourceInfo resourceInfo) {
        Traced tracedAnnotation = resourceInfo.getResourceMethod().getAnnotation(Traced.class);
        if (tracedAnnotation == null) {
            tracedAnnotation = resourceInfo.getResourceClass().getAnnotation(Traced.class);
        }

        return tracedAnnotation;
    }

    protected boolean tracingDisabled(ResourceInfo resourceInfo) {
        Traced traced = closestTracedAnnotation(resourceInfo);
        return traced == null ? !builder.allTraced : !traced.value();
    }

    protected String operationName(ResourceInfo resourceInfo) {
        Traced traced = closestTracedAnnotation(resourceInfo);
        return traced != null && !traced.operationName().isEmpty()  ? traced.operationName() : null;
    }

    /**
     * Builder for creating JAX-RS dynamic feature for tracing server requests.
     *
     * By default span's operation name is HTTP method and span is decorated with
     * {@link ServerSpanDecorator#STANDARD_TAGS} which adds standard tags.
     * If you want to set different span name provide custom span decorator {@link ServerSpanDecorator}.
     */
    public static class Builder {
        private final Tracer tracer;
        private boolean allTraced;
        private List<ServerSpanDecorator> spanDecorators;
        private List<InterceptorSpanDecorator> serializationSpanDecorators;