content: /*
   * Copyright The OpenTelemetry Authors
   * SPDX-License-Identifier: Apache-2.0
   */
  
  package io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal;
  
  import io.opentelemetry.context.Context;
  import io.opentelemetry.context.Scope;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Proxy;
  import java.util.ArrayList;
  import java.util.List;
  import org.eclipse.jetty.client.Response;
  
  /**
   * This class is internal and is hence not for public use. Its APIs are unstable and can change at
   * any time.
   */
  public final class JettyClientWrapUtil {
    private static final Class<?>[] LISTENER_INTERFACES = {
      Response.CompleteListener.class,
      Response.FailureListener.class,
      Response.SuccessListener.class,
      Response.AsyncContentListener.class,
      Response.ContentSourceListener.class,
      Response.ContentListener.class,
      Response.HeadersListener.class,
      Response.HeaderListener.class,
      Response.BeginListener.class
    };
  
    private JettyClientWrapUtil() {}
  
    /**
     * Utility to wrap the response listeners only, this includes the important CompleteListener.
     *
     * @param context top level context that is above the Jetty client span context
     * @param listener listener passed to Jetty client send() method
     * @return wrapped listener
     */
    public static Response.CompleteListener wrapTheListener(
        Response.CompleteListener listener, Context context) {
      if (listener == null) {
        return listener;
      }
  
      Class<?> listenerClass = listener.getClass();
      List<Class<?>> interfaces = new ArrayList<>();
      for (Class<?> type : LISTENER_INTERFACES) {
        if (type.isInstance(listener)) {
          interfaces.add(type);
        }
      }
      if (interfaces.isEmpty()) {
        return listener;
      }
  
      return (Response.CompleteListener)
          Proxy.newProxyInstance(
              listenerClass.getClassLoader(),
              interfaces.toArray(new Class<?>[0]),
              (proxy, method, args) -> {
                try (Scope ignored = context.makeCurrent()) {
                  return method.invoke(listener, args);
                } catch (InvocationTargetException exception) {
                  throw exception.getCause();
                }
              });
    }
  }
  