class AccessValidatorController {

    void validateAccess(File propertiesFile, Boolean messageFlag) throws IOException, ApiException
    {
        // Load properties.
        propertiesHelper.loadProperties(propertiesFile);

        // Check properties
        herdApiClientOperations.checkPropertiesFile(propertiesHelper, messageFlag);

        // Create the API client to a specific REST endpoint with proper authentication.
        ApiClient apiClient = new ApiClient();
        apiClient.setBasePath(propertiesHelper.getProperty(HERD_BASE_URL_PROPERTY));
        apiClient.setUsername(propertiesHelper.getProperty(HERD_USERNAME_PROPERTY));
        apiClient.setPassword(propertiesHelper.getProperty(HERD_PASSWORD_PROPERTY));

        // Setup specific API classes.
        ApplicationApi applicationApi = new ApplicationApi(apiClient);
        CurrentUserApi currentUserApi = new CurrentUserApi(apiClient);

        // Retrieve build information from the registration server.
        LOGGER.info("Retrieving build information from the registration server...");
        LOGGER.info("{}", herdApiClientOperations.applicationGetBuildInfo(applicationApi));

        // Retrieve user information from the registration server.
        LOGGER.info("Retrieving user information from the registration server...");
        LOGGER.info("{}", herdApiClientOperations.currentUserGetCurrentUser(currentUserApi));

        // Create AWS client configuration.
        ClientConfiguration clientConfiguration = new ClientConfiguration();

        // Get AWS region.
        String awsRegion = propertiesHelper.getProperty(AWS_REGION_PROPERTY);

        // Get ARN for the AWS role to assume.
        String awsRoleArn = propertiesHelper.getProperty(AWS_ROLE_ARN_PROPERTY);
        LOGGER.info("Assuming \"{}\" AWS role...", awsRoleArn);
        AWSCredentialsProvider awsCredentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(awsRoleArn, UUID.randomUUID().toString())
            .withStsClient(AWSSecurityTokenServiceClientBuilder.standard().withClientConfiguration(clientConfiguration).withRegion(awsRegion).build()).build();

        // Create AWS S3 client using the assumed role.
        LOGGER.info("Creating AWS S3 client using role: \"{}\".", awsRoleArn);

        AmazonS3 amazonS3 =
            AmazonS3ClientBuilder.standard().withCredentials(awsCredentialsProvider).withClientConfiguration(clientConfiguration).withRegion(awsRegion).build();

        // Create AWS SQS client using the assumed role.
        LOGGER.info("Creating AWS SQS client using role: \"{}\".", awsRoleArn);

        AmazonSQS amazonSQS =
            AmazonSQSClientBuilder.standard().withCredentials(awsCredentialsProvider).withClientConfiguration(clientConfiguration).withRegion(awsRegion)
                .build();

        BusinessObjectDataKey bdataKey;

        // Check if -m flag passed
        if (messageFlag)
        {
            String sqsQueueUrl = propertiesHelper.getProperty(AWS_SQS_QUEUE_URL_PROPERTY);
            LOGGER.info("Getting message from SQS queue: {}", sqsQueueUrl);
            bdataKey = herdApiClientOperations.getBdataKeySqs(amazonSQS, sqsQueueUrl);
        }
        else
        {
            LOGGER.info("Creating BusinessObjectDataKey from properties file");
            bdataKey = getBusinessObjectDataKeyFromPropertiesFile();
        }
        LOGGER.info("Using business object data key: {}", bdataKey);

        BusinessObjectDataApi businessObjectDataApi = new BusinessObjectDataApi(apiClient);

        // Retrieve business object data from the registration server.
        LOGGER.info("Retrieving business object data information from the registration server...");
        BusinessObjectData businessObjectData = herdApiClientOperations
            .businessObjectDataGetBusinessObjectData(businessObjectDataApi, bdataKey.getNamespace(), bdataKey.getBusinessObjectDefinitionName(),
                bdataKey.getBusinessObjectFormatUsage(), bdataKey.getBusinessObjectFormatFileType(), null, bdataKey.getPartitionValue(),
                StringUtils.join(bdataKey.getSubPartitionValues(), "|"), bdataKey.getBusinessObjectFormatVersion(), bdataKey.getBusinessObjectDataVersion(),
                null, false, false, false);

        // Log business object data information returned by the registration server.
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        LOGGER.info("{}", gson.toJson(businessObjectData));

        // Check if retrieved business object data has storage unit registered with it.
        Assert.isTrue(CollectionUtils.isNotEmpty(businessObjectData.getStorageUnits()), "Business object data has no storage unit registered with it.");
        Assert.isTrue(businessObjectData.getStorageUnits().get(0).getStorage() != null, "Business object data storage unit does not have storage information.");

        // Get S3 bucket name.
        String bucketName = null;
        for (Attribute attribute : businessObjectData.getStorageUnits().get(0).getStorage().getAttributes())
        {
            if (StringUtils.equals(attribute.getName(), S3_BUCKET_NAME_ATTRIBUTE))
            {
                bucketName = attribute.getValue();
                break;
            }
        }
        Assert.isTrue(StringUtils.isNotBlank(bucketName), "S3 bucket name is not configured for the storage.");

        // Validate that S3 files registered with the business object data under can be streamed to disk.
        LOGGER.info("Validating that S3 files registered with the business object data are downloadable.");

        // Initialize a flag to be used to determine if we did not find any non-zero byte files registered for this business object data.
        boolean readAccessValidated = false;

        // If business object data has registered storage files, we go though the list until we fail
        // accessing S3 metadata or find a non-zero byte file that we can try to download.
        if (CollectionUtils.isNotEmpty(businessObjectData.getStorageUnits().get(0).getStorageFiles()))
        {
            // Loop through the list of storage files and attempt to read at least one file which has valid content.
            for (StorageFile storageFile : businessObjectData.getStorageUnits().get(0).getStorageFiles())
            {
                LOGGER.info("Attempting to read \"{}/{}\" S3 file...", bucketName, storageFile.getFilePath());

                // Get S3 object metadata.
                ObjectMetadata objectMetadata = s3Operations.getObjectMetadata(bucketName, storageFile.getFilePath(), amazonS3);

                // Try to verify read access to the S3 object.
                if (verifyReadAccessToS3Object(bucketName, storageFile.getFilePath(), objectMetadata.getContentLength(), amazonS3))
                {
                    readAccessValidated = true;
                    break;
                }
            }
        }
        // If business object data has no registered storage files, we go though the list of S3 files found under
        // the storage unit directory path (S3 key prefix) until we find a non-zero byte file that we can try to download.
        else
        {
            // Check if storage unit has a non-blank directory path.
            Assert.isTrue(businessObjectData.getStorageUnits().get(0).getStorageDirectory() != null &&
                    StringUtils.isNotBlank(businessObjectData.getStorageUnits().get(0).getStorageDirectory().getDirectoryPath()),
                "" + "No storage files or directory path is registered with the business object data storage unit.");

            // Since storage unit directory path represents a directory, we add a trailing '/' character to it.
            String getS3KeyPrefix = StringUtils.appendIfMissing(businessObjectData.getStorageUnits().get(0).getStorageDirectory().getDirectoryPath(), "/");

            // List all S3 files located under the S3 prefix.
            // We are not using pagination here assuming that AWS page limit is enough to find at least one non-zero byte file.
            LOGGER.info("Attempting to list S3 files located under \"{}/{}\" S3 key prefix...", bucketName, getS3KeyPrefix);
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest().withBucketName(bucketName).withPrefix(getS3KeyPrefix);
            ObjectListing objectListing = s3Operations.listObjects(listObjectsRequest, amazonS3);

            for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries())
            {
                // Try to verify read access to the S3 object.
                if (verifyReadAccessToS3Object(bucketName, objectSummary.getKey(), objectSummary.getSize(), amazonS3))
                {
                    readAccessValidated = true;
                    break;
                }
            }
        }

        // Report success if we were able to find a non-zero byte file and verify read
        // access by downloading some number of bytes from the beginning of the file.
        if (readAccessValidated)
        {
            LOGGER.info("{}Finished: SUCCESS", LINE_FEED);
        }
        // Otherwise, report a failure.
        else
        {
            LOGGER.error("{}Could not read valid content from any file: FAILURE", LINE_FEED);
        }
    }

}