// Path: src/main/java/com/google/fleetengine/auth/token/factory/signer/SigningTokenException.java
// public class SigningTokenException extends Exception {
//   /**
//    * Constructs a {@code SigningTokenException} with the specified detail message.
//    *
//    * @param message The detail message (which is saved for later retrieval by the {@link
//    *     #getMessage()} method)
//    */
//   public SigningTokenException(String message) {
//     this(message, null);
//   }
// 
//   /**
//    * Constructs a {@code SigningTokenException} with the specified detail message.
//    *
//    * @param message The detail message (which is saved for later retrieval by the {@link
//    *     #getMessage()} method)
//    * @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
//    *     (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
//    */
//   public SigningTokenException(String message, Throwable cause) {
//     super(message, cause);
//   }
// }


import com.google.api.gax.rpc.FixedHeaderProvider;
import com.google.api.gax.rpc.HeaderProvider;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.fleetengine.auth.token.factory.signer.SigningTokenException;
import java.util.Map;
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.fleetengine.auth.client;


/**
 * Provides a valid Fleet Engine JWT on the header of an outgoing gRPC request.
 *
 * <p>A secondary header provider can be added that provides additional headers. In the event that
 * the other header provider also contains an authorization header, that header is overwritten.
 *
 * <p>Works with generated GAPIC classes. For correct usage, see {@link
 * FleetEngineClientSettingsModifier}.
 */
public class FleetEngineAuthClientHeaderProvider implements HeaderProvider {
  private static final String AUTHORIZATION_HEADER_NAME = "authorization";

  @VisibleForTesting final FleetEngineTokenProvider tokenProvider;

  @VisibleForTesting final HeaderProvider underlyingHeaderProvider;

  /**
   * Creates {@link FleetEngineAuthClientHeaderProvider}.
   *
   * @param tokenProvider provides fleet engine tokens
   * @return constructed header provider
   */
  public static FleetEngineAuthClientHeaderProvider create(FleetEngineTokenProvider tokenProvider) {
    return new FleetEngineAuthClientHeaderProvider(tokenProvider, FixedHeaderProvider.create());
  }

  /**
   * Creates {@link FleetEngineAuthClientHeaderProvider}.
   *
   * @param tokenProvider provides fleet engine tokens
   * @param underlyingHeaderProvider provides additional headers to the outbound request.
   * @return constructed header provider
   */
  public static FleetEngineAuthClientHeaderProvider create(
      FleetEngineTokenProvider tokenProvider, HeaderProvider underlyingHeaderProvider) {
    return new FleetEngineAuthClientHeaderProvider(tokenProvider, underlyingHeaderProvider);
  }

  private FleetEngineAuthClientHeaderProvider(
      FleetEngineTokenProvider tokenProvider, HeaderProvider underlyingHeaderProvider) {
    this.underlyingHeaderProvider = underlyingHeaderProvider;
    this.tokenProvider = tokenProvider;
  }

  /** {@inheritDoc} */
  @Override
  public Map<String, String> getHeaders() {
    try {
      // If the underlying provider has an authorization header, skip.
      Map<String, String> underlyingMap =
          Maps.filterEntries(
              underlyingHeaderProvider.getHeaders(),
              entry -> !AUTHORIZATION_HEADER_NAME.equals(entry.getKey()));
      return new ImmutableMap.Builder<String, String>()
          .putAll(underlyingMap)
          .put(
              AUTHORIZATION_HEADER_NAME,
              String.format("Bearer %s", tokenProvider.getSignedToken().jwt()))
          .buildOrThrow();
// Path: src/main/java/com/google/fleetengine/auth/token/factory/signer/SigningTokenException.java
// public class SigningTokenException extends Exception {
//   /**
//    * Constructs a {@code SigningTokenException} with the specified detail message.
//    *
//    * @param message The detail message (which is saved for later retrieval by the {@link
//    *     #getMessage()} method)
//    */
//   public SigningTokenException(String message) {
//     this(message, null);
//   }
// 
//   /**
//    * Constructs a {@code SigningTokenException} with the specified detail message.
//    *
//    * @param message The detail message (which is saved for later retrieval by the {@link
//    *     #getMessage()} method)
//    * @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
//    *     (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
//    */
//   public SigningTokenException(String message, Throwable cause) {
//     super(message, cause);
//   }
// }


// Path: src/main/java/com/google/fleetengine/auth/client/FleetEngineAuthClientHeaderProvider.java
import com.google.api.gax.rpc.FixedHeaderProvider;
import com.google.api.gax.rpc.HeaderProvider;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.fleetengine.auth.token.factory.signer.SigningTokenException;
import java.util.Map;

// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.fleetengine.auth.client;


/**
 * Provides a valid Fleet Engine JWT on the header of an outgoing gRPC request.
 *
 * <p>A secondary header provider can be added that provides additional headers. In the event that
 * the other header provider also contains an authorization header, that header is overwritten.
 *
 * <p>Works with generated GAPIC classes. For correct usage, see {@link
 * FleetEngineClientSettingsModifier}.
 */
public class FleetEngineAuthClientHeaderProvider implements HeaderProvider {
  private static final String AUTHORIZATION_HEADER_NAME = "authorization";

  @VisibleForTesting final FleetEngineTokenProvider tokenProvider;

  @VisibleForTesting final HeaderProvider underlyingHeaderProvider;

  /**
   * Creates {@link FleetEngineAuthClientHeaderProvider}.
   *
   * @param tokenProvider provides fleet engine tokens
   * @return constructed header provider
   */
  public static FleetEngineAuthClientHeaderProvider create(FleetEngineTokenProvider tokenProvider) {
    return new FleetEngineAuthClientHeaderProvider(tokenProvider, FixedHeaderProvider.create());
  }

  /**
   * Creates {@link FleetEngineAuthClientHeaderProvider}.
   *
   * @param tokenProvider provides fleet engine tokens
   * @param underlyingHeaderProvider provides additional headers to the outbound request.
   * @return constructed header provider
   */
  public static FleetEngineAuthClientHeaderProvider create(
      FleetEngineTokenProvider tokenProvider, HeaderProvider underlyingHeaderProvider) {
    return new FleetEngineAuthClientHeaderProvider(tokenProvider, underlyingHeaderProvider);
  }

  private FleetEngineAuthClientHeaderProvider(
      FleetEngineTokenProvider tokenProvider, HeaderProvider underlyingHeaderProvider) {
    this.underlyingHeaderProvider = underlyingHeaderProvider;
    this.tokenProvider = tokenProvider;
  }

  /** {@inheritDoc} */
  @Override
  public Map<String, String> getHeaders() {
    try {
      // If the underlying provider has an authorization header, skip.
      Map<String, String> underlyingMap =
          Maps.filterEntries(
              underlyingHeaderProvider.getHeaders(),
              entry -> !AUTHORIZATION_HEADER_NAME.equals(entry.getKey()));
      return new ImmutableMap.Builder<String, String>()
          .putAll(underlyingMap)
          .put(
              AUTHORIZATION_HEADER_NAME,
              String.format("Bearer %s", tokenProvider.getSignedToken().jwt()))
          .buildOrThrow();
    } catch (SigningTokenException e) {