Configuring Thread-Safe HTTP Connection Pooling for the Genesys Cloud Java SDK

Configuring Thread-Safe HTTP Connection Pooling for the Genesys Cloud Java SDK

What You Will Build

  • A production-ready Java utility class that initializes a thread-safe, connection-pooled ApiClient instance for the Genesys Cloud Platform SDK.
  • An implementation that handles OAuth2 token refresh asynchronously without blocking application threads.
  • A demonstration of executing parallel API requests using the configured client.

Prerequisites

  • OAuth Client Type: Confidential Client (Client Credentials Grant).
  • Required Scopes: view:users (for the example query), offline_access (optional but recommended for token caching strategies).
  • SDK Version: genesyscloud-platform-java-client version 13.0.0 or later.
  • Language/Runtime: Java 11 or higher.
  • External Dependencies:
    • com.twilio:genesyscloud-platform-java-client
    • org.apache.httpcomponents:httpclient (managed by SDK, but good to know)
    • org.slf4j:slf4j-api (for logging)

Authentication Setup

The Genesys Cloud Java SDK relies on the ApiClient class to manage HTTP connections and authentication tokens. By default, the SDK creates a new HTTP client instance for each ApiClient initialization, which is inefficient for high-throughput applications. To implement connection pooling, you must manually configure the underlying Apache HttpClient and inject it into the SDK.

The authentication flow uses the Client Credentials Grant. The SDK handles the token retrieval and refresh automatically, provided you supply the correct credentials. However, because the token refresh mechanism is internal to the ApiClient, you must ensure that the ApiClient instance is shared across threads to avoid redundant token requests and connection churn.

Step 1: Initialize the Thread-Safe ApiClient with Connection Pooling

The core of this tutorial is creating a singleton or static instance of ApiClient that uses a shared PoolingHttpClientConnectionManager. This manager maintains a pool of reusable connections, reducing latency for subsequent requests and preventing socket exhaustion under load.

import com.mypurecloud.v2.ApiClient;
import com.mypurecloud.v2.auth.OAuth;
import com.mypurecloud.v2.auth.OAuthFlow;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContexts;
import javax.net.ssl.SSLContext;
import java.security.KeyStore;
import java.io.FileInputStream;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.io.IOException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

public class GenesysClientFactory {

    private static volatile ApiClient apiClient;
    private static final String REGION = "mypurecloud.com";
    private static final String CLIENT_ID = System.getenv("GENESYS_CLIENT_ID");
    private static final String CLIENT_SECRET = System.getenv("GENESYS_CLIENT_SECRET");

    // Private constructor to prevent instantiation
    private GenesysClientFactory() {}

    /**
     * Returns a thread-safe ApiClient instance with connection pooling.
     * Uses double-checked locking for efficient synchronization.
     */
    public static ApiClient getApiClient() {
        if (apiClient == null) {
            synchronized (GenesysClientFactory.class) {
                if (apiClient == null) {
                    apiClient = createPooledApiClient();
                }
            }
        }
        return apiClient;
    }

    private static ApiClient createPooledApiClient() {
        try {
            // 1. Create an SSL Context (using default trust store for simplicity)
            SSLContext sslContext = SSLContexts.createDefault();
            SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);

            // 2. Register socket factories for HTTP and HTTPS
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslSocketFactory)
                    .build();

            // 3. Initialize the Connection Pool
            // Max total connections: 200
            // Max connections per route: 20
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            connectionManager.setMaxTotal(200);
            connectionManager.setDefaultMaxPerRoute(20);

            // 4. Build the HttpClient with the connection manager
            CloseableHttpClient httpClient = HttpClients.custom()
                    .setConnectionManager(connectionManager)
                    .build();

            // 5. Initialize the Genesys API Client
            // Base URL for the Genesys Platform
            String baseUrl = "https://" + REGION;
            apiClient = new ApiClient(baseUrl);

            // 6. Inject the custom HttpClient into the API Client
            // This replaces the default HTTP client with our pooled one
            apiClient.setHttpClient(httpClient);

            // 7. Configure OAuth
            OAuth oAuth = apiClient.getOAuth();
            oAuth.setClientId(CLIENT_ID);
            oAuth.setClientSecret(CLIENT_SECRET);
            oAuth.setOAuthFlow(OAuthFlow.CLIENT_CREDENTIALS);

            // Optional: Set a custom token refresh threshold (default is usually sufficient)
            // oAuth.setAccessTokenRefreshThresholdSeconds(60);

            // Initialize the OAuth token immediately
            oAuth.init();

            return apiClient;

        } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException 
                 | CertificateException | IOException e) {
            throw new RuntimeException("Failed to initialize Genesys API Client", e);
        }
    }
}

Step 2: Implementing Parallel API Requests

With a thread-safe ApiClient in place, you can now make multiple concurrent requests. The SDK methods are not thread-safe by themselves, but the underlying HTTP client and the OAuth token manager within ApiClient are designed to be shared.

Critical Note: Do not create a new UsersApi or other API wrapper instance for every thread. Instead, create a single instance of the API wrapper per thread, or reuse it if you ensure proper synchronization (though per-thread instances are safer and easier). The ApiClient itself must be shared.

Here is an example of fetching user details for multiple users in parallel using Java’s CompletableFuture.

import com.mypurecloud.v2.ApiClient;
import com.mypurecloud.v2.api.UsersApi;
import com.mypurecloud.v2.model.User;
import com.mypurecloud.v2.model.UserSearchResponse;
import com.mypurecloud.v2.auth.OAuth;

import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class ParallelUserFetcher {

    private final ApiClient apiClient;
    private final ExecutorService executor;

    public ParallelUserFetcher(ApiClient apiClient, int threadCount) {
        this.apiClient = apiClient;
        this.executor = Executors.newFixedThreadPool(threadCount);
    }

    /**
     * Fetches user details for a list of user IDs concurrently.
     *
     * @param userIds List of user IDs to fetch
     * @return List of User objects
     */
    public List<User> fetchUsersConcurrently(List<String> userIds) {
        List<CompletableFuture<User>> futures = new ArrayList<>();

        for (String userId : userIds) {
            // Create a new API instance for each thread/task to ensure thread safety
            // The ApiClient is shared, but the API wrapper should not be shared across threads
            UsersApi usersApi = new UsersApi(apiClient);

            CompletableFuture<User> future = CompletableFuture.supplyAsync(() -> {
                try {
                    // Fetch user details
                    // Scope: view:users
                    return usersApi.getUser(userId);
                } catch (Exception e) {
                    // Handle 404, 429, or network errors
                    System.err.println("Error fetching user " + userId + ": " + e.getMessage());
                    return null;
                }
            }, executor);

            futures.add(future);
        }

        // Wait for all futures to complete and collect results
        return futures.stream()
                .map(CompletableFuture::join)
                .filter(user -> user != null)
                .collect(Collectors.toList());
    }

    public void shutdown() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

Step 3: Handling Rate Limits (429) and Retries

Even with connection pooling, you will hit rate limits. The Genesys Cloud API returns 429 Too Many Requests when you exceed the allowed rate. The Java SDK does not automatically retry 429 errors by default in all versions, so implementing a retry mechanism with exponential backoff is crucial for production stability.

You can extend the ApiClient or use a wrapper to handle retries. Here is a simple retry utility that wraps the API call.

import java.io.IOException;
import java.net.http.HttpTimeoutException;
import java.time.Duration;

@FunctionalInterface
interface ApiCall<T> {
    T execute() throws Exception;
}

public class RetryUtils {

    private static final int MAX_RETRIES = 3;
    private static final long INITIAL_BACKOFF_MS = 1000;

    /**
     * Executes an API call with exponential backoff on 429 or 5xx errors.
     *
     * @param apiCall The API call to execute
     * @param <T> The return type of the API call
     * @return The result of the API call
     * @throws Exception If the call fails after max retries
     */
    public static <T> T executeWithRetry(ApiCall<T> apiCall) throws Exception {
        Exception lastException = null;
        long backoff = INITIAL_BACKOFF_MS;

        for (int attempt = 0; attempt <= MAX_RETRIES; attempt++) {
            try {
                return apiCall.execute();
            } catch (com.mypurecloud.v2.ApiException e) {
                // Check for 429 Too Many Requests or 5xx Server Errors
                if (e.getCode() == 429 || (e.getCode() >= 500 && e.getCode() < 600)) {
                    lastException = e;
                    System.out.println("Retry attempt " + (attempt + 1) + " after " + e.getCode() + " error. Waiting " + backoff + "ms...");
                    Thread.sleep(backoff);
                    backoff *= 2; // Exponential backoff
                } else {
                    // Other errors (401, 403, 404) should not be retried
                    throw e;
                }
            } catch (IOException e) {
                lastException = e;
                System.out.println("Retry attempt " + (attempt + 1) + " after IOException. Waiting " + backoff + "ms...");
                Thread.sleep(backoff);
                backoff *= 2;
            }
        }

        throw new RuntimeException("API call failed after " + MAX_RETRIES + " retries", lastException);
    }
}

To use this, wrap your API calls:

User user = RetryUtils.executeWithRetry(() -> usersApi.getUser(userId));

Complete Working Example

This example combines all the previous steps into a single runnable class. It initializes the pooled client, fetches a list of users, and then fetches detailed information for each user in parallel with retry logic.

import com.mypurecloud.v2.ApiClient;
import com.mypurecloud.v2.api.UsersApi;
import com.mypurecloud.v2.model.User;
import com.mypurecloud.v2.model.UserSearchResponse;
import com.mypurecloud.v2.auth.OAuth;
import com.mypurecloud.v2.auth.OAuthFlow;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

public class GenesysPoolExample {

    public static void main(String[] args) {
        // Initialize the pooled API client
        ApiClient apiClient = GenesysClientFactory.getApiClient();

        // Create a parallel fetcher with 10 threads
        ParallelUserFetcher fetcher = new ParallelUserFetcher(apiClient, 10);

        try {
            // Step 1: Search for users to get IDs
            UsersApi usersApi = new UsersApi(apiClient);
            String query = "divisionId:*"; // Search all users in all divisions
            UserSearchResponse searchResponse = usersApi.postUsersSearch(
                    query, 
                    null, // email
                    10, // pageSize
                    null, // page
                    null, // sortBy
                    null, // sortOrder
                    null, // expansion
                    null, // divisionId
                    null, // userId
                    null, // groupId
                    null, // roleIds
                    null, // queueIds
                    null, // skillIds
                    null, // languageIds
                    null, // presenceIds
                    null, // customAttributeIds
                    null, // customAttributeValues
                    null, // customAttributeFilter
                    null, // customAttributeFilterType
                    null, // customAttributeFilterValue
                    null, // customAttributeFilterOperator
                    null, // customAttributeFilterCondition
                    null, // customAttributeFilterConditionType
                    null, // customAttributeFilterConditionValue
                    null, // customAttributeFilterConditionOperator
                    null, // customAttributeFilterConditionCondition
                    null, // customAttributeFilterConditionConditionType
                    null, // customAttributeFilterConditionConditionValue
                    null, // customAttributeFilterConditionConditionOperator
                    null, // customAttributeFilterConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionType
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionValue
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionOperator
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition
                    null, // customAttributeFilterConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionConditionCondition