Class EquinixClient

java.lang.Object
com.eqixiac.equinix.core.client.EquinixClient
All Implemented Interfaces:
Closeable, AutoCloseable

public class EquinixClient extends Object implements Closeable
Low-level transport client: owns the token lifecycle, the pooled HTTP client, the resolved endpoint, and the merged apiParams catalogue, and signs and dispatches every request. The public facade EquinixClient and the domain clients delegate to an instance of this class.

Token sources

A client is built over exactly one token source: OAuth2 client credentials (EquinixCredentialsProvider; the facade wires the token mint through setAuthenticator(Runnable)), or a BearerTokenProvider that supplies ready-made tokens (for example an STS-issued access-policy token). Either way the token is obtained lazily on the first authenticated request and again when it expires, single-flight.

401 recovery

When an authenticated request is answered with HTTP 401 the cached token is discarded, a new one is obtained once (single-flight: concurrent requests rejected with the same token cause one token request) and the request is replayed once. A second 401 is thrown. There is no replay for the token request itself, for endpoints declared "unauthenticated", or when no token source is wired. Replaying is safe for every method because a 401 means the request was rejected before it was processed.

Author:
ianjones
  • Constructor Details

    • EquinixClient

      public EquinixClient(EquinixCredentials equinixCredentials, boolean isSandBoxed)
      Creates a transport client over fixed OAuth2 client credentials.
      Parameters:
      equinixCredentials - the client credentials
      isSandBoxed - true for the sandbox environment; false for production
    • EquinixClient

      public EquinixClient(EquinixCredentialsProvider credentialsProvider, boolean isSandBoxed)
      Creates a transport client that resolves its credentials through the given provider. The provider is consulted on each authentication (first call and re-auth on expiry), so a custom provider can rotate the underlying credentials without the client being rebuilt.
      Parameters:
      credentialsProvider - supplies the OAuth2 credentials to authenticate with
      isSandBoxed - true for the sandbox environment; false for production
    • EquinixClient

      public EquinixClient(BearerTokenProvider bearerTokenProvider, boolean isSandBoxed)
      Creates a transport client that signs requests with tokens from the given provider instead of minting OAuth2 client-credentials tokens. No token-mint authenticator is needed or used: the provider is asked for a token on the first authenticated call, before a known expiry, and once after an HTTP 401.
      Parameters:
      bearerTokenProvider - supplies the bearer tokens
      isSandBoxed - true for the sandbox environment; false for production
  • Method Details

    • setClock

      public void setClock(Clock clock)
      Replaces the clock used to judge token expiry and Retry-After dates (default Clock.systemUTC()). Intended for deterministic tests and simulations.
      Parameters:
      clock - the clock; must not be null
    • setEndPoint

      public void setEndPoint(String endPoint) throws IllegalArgumentException
      Replaces the client-wide endpoint (a gateway, proxy or WireMock); from then on it wins over the catalogue's per-domain hosts unless a domain override is set.
      Parameters:
      endPoint - the host, with or without scheme
      Throws:
      IllegalArgumentException - if the endpoint is not a valid URI
    • setDomainEndPoint

      public void setDomainEndPoint(String functionalArea, String endPoint)
      Routes one functional area (for example "IAM" or "STS") to its own host, overriding both the catalogue's per-domain host and setEndPoint(String).
      Parameters:
      functionalArea - the functional-area key from the apiParams catalogue
      endPoint - the host (with or without scheme); null removes the override
    • getEndPointFor

      public URI getEndPointFor(String functionalArea)
      Resolves the host a functional area's requests are sent to. Precedence:
      1. an explicit setDomainEndPoint(String, String) override;
      2. the client-wide endpoint, when a caller replaced it with setEndPoint(String);
      3. the functional area's own hostName / sandboxHostName in its apiParams resource (IAM is served by access.eqix.equinix.com and STS by sts.eqix.equinix.com; api.equinix.com answers 404 for both);
      4. the client-wide default endpoint.
      Parameters:
      functionalArea - the functional-area key, may be null
      Returns:
      the endpoint for that area, never null
    • setRetryPolicy

      public void setRetryPolicy(RetryPolicy retryPolicy)
      Overrides the automatic retry behavior for transient failures (429/5xx, transient IO).
      Parameters:
      retryPolicy - the policy to apply; RetryPolicy.none() disables retries
    • setCircuitBreaker

      public void setCircuitBreaker(CircuitBreaker circuitBreaker)
      Enables (or, with null, disables) the opt-in circuit breaker consulted for every request attempt. See CircuitBreaker for the open/half-open/closed semantics. Disabled by default.
      Parameters:
      circuitBreaker - the breaker to enforce, or null to disable
    • appendApiParams

      public void appendApiParams(String fileName) throws EquinixClientException
      Merges a domain's apiParams resource into the shared catalogue. Thread-safe: the merge is copy-on-write under apiParamsLock and published atomically through the volatile clientResourceFile field (read via the Lombok-generated getClientResourceFile()), so request threads reading the tree concurrently (Jackson's ObjectNode is not safe for concurrent read/write) always see either the old or the fully-merged catalogue.
      Parameters:
      fileName - the classpath resource name (e.g. json/apiParams_Fabric.json)
      Throws:
      EquinixClientException - if the resource is missing, malformed, or does not declare a functionalAreas object
    • invoke

      public <T> EquinixResponse<T> invoke(EquinixRequest<T> equinixRequest)
      Resolves, signs and dispatches a request, with the retry policy, the circuit breaker and the one-shot 401 recovery described on this class.
      Type Parameters:
      T - the response payload type
      Parameters:
      equinixRequest - the request to send
      Returns:
      the successful response
      Throws:
      EquinixClientException - if the request cannot be built or sent
      EquinixServiceException - if the API answers with an error
    • isSandBoxed

      public boolean isSandBoxed()
      Returns:
      a boolean.
    • getOAuthToken

      public OAuthToken getOAuthToken()
      Returns the currently published OAuth token, or null if the client has not authenticated yet.

      This is a lock-free volatile read returning the latest published instance. For an atomic validity-then-use decision under concurrency, prefer the internal single-flight path in setStandardHeaders(EquinixRequest) which captures a consistent snapshot under tokenLock.

      Returns:
      the current OAuthToken, may be null.
    • setOAuthToken

      public void setOAuthToken(OAuthToken oAuthToken)
      Publishes a (re)authenticated OAuth token for use by subsequent requests.

      Publication is serialized through tokenLock so that a token obtained by a single-flight refresh becomes visible atomically with respect to other threads inspecting validity. Once stored, the volatile field guarantees the new instance is visible to all threads.

      Parameters:
      oAuthToken - the freshly obtained token, may be null to clear.
    • setAuthenticator

      public void setAuthenticator(Runnable authenticator)
      Wires the callback used to mint and publish an OAuth token for lazy authentication and re-authentication on expiry or after a 401. The facade client supplies this; the core client invokes it when a request needs a token and none valid is published. Ignored when this client was built over a BearerTokenProvider, which then is the only token source.
      Parameters:
      authenticator - the token-acquisition callback (it must publish via setOAuthToken(OAuthToken))
    • authenticate

      public void authenticate()
      Forces (re)authentication from the wired token source (the client-credentials authenticator or the BearerTokenProvider), single-flight under tokenLock. This is the explicit authenticate() entry point. The authenticating guard means the token request it issues (which itself flows through setStandardHeaders(EquinixRequest)) does not recurse into another authentication. No-op when no token source is wired.
    • close

      public void close() throws IOException
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Throws:
      IOException