From e094b95bb0b43a36e778f0d121aecfd29e6180a7 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 10 Jul 2026 14:25:19 +0530 Subject: [PATCH 01/28] SK-2967 split out the common things from v2 and v3 into common module --- common/pom.xml | 24 + .../main/java/com/skyflow/BaseSkyflow.java | 36 ++ .../java/com/skyflow/BaseVaultClient.java | 93 +++ .../com/skyflow/config/BaseCredentials.java | 36 +- .../com/skyflow/config/BaseVaultConfig.java | 18 +- .../src}/main/java/com/skyflow/enums/Env.java | 0 .../java/com/skyflow/enums/InterfaceName.java | 0 .../main/java/com/skyflow/enums/LogLevel.java | 0 .../java/com/skyflow/errors/ErrorCode.java | 0 .../java/com/skyflow/errors/ErrorMessage.java | 210 +++++++ .../java/com/skyflow/errors/HttpStatus.java | 0 .../com/skyflow/errors/SkyflowException.java | 135 +++++ .../generated/auth/rest/ApiClient.java | 29 + .../generated/auth/rest/ApiClientBuilder.java | 67 +++ .../generated/auth/rest/AsyncApiClient.java | 29 + .../auth/rest/AsyncApiClientBuilder.java | 67 +++ .../auth/rest/core/ApiClientApiException.java | 74 +++ .../auth/rest/core/ApiClientException.java | 17 + .../auth/rest/core/ApiClientHttpResponse.java | 38 ++ .../auth/rest/core/ClientOptions.java | 171 ++++++ .../auth/rest/core/DateTimeDeserializer.java | 56 ++ .../generated/auth/rest/core/Environment.java | 24 + .../generated/auth/rest/core/FileStream.java | 61 ++ .../rest/core/InputStreamRequestBody.java | 80 +++ .../generated/auth/rest/core/MediaTypes.java | 13 + .../generated/auth/rest/core/Nullable.java | 140 +++++ .../rest/core/NullableNonemptyFilter.java | 19 + .../auth/rest/core/ObjectMappers.java | 37 ++ .../auth/rest/core/QueryStringMapper.java | 139 +++++ .../auth/rest/core/RequestOptions.java | 101 ++++ .../rest/core/ResponseBodyInputStream.java | 46 ++ .../auth/rest/core/ResponseBodyReader.java | 45 ++ .../auth/rest/core/RetryInterceptor.java | 79 +++ .../generated/auth/rest/core/Stream.java | 97 ++++ .../generated/auth/rest/core/Suppliers.java | 23 + .../auth/rest/errors/BadRequestError.java | 34 ++ .../auth/rest/errors/HttpStatus.java | 15 + .../auth/rest/errors/NotFoundError.java | 34 ++ .../auth/rest/errors/UnauthorizedError.java | 34 ++ .../AsyncAuthenticationClient.java | 11 +- .../AsyncRawAuthenticationClient.java | 44 +- .../authentication/AuthenticationClient.java | 10 +- .../RawAuthenticationClient.java | 43 +- .../requests/V1GetAuthTokenRequest.java | 17 +- .../rest/types/V1GetAuthTokenResponse.java | 125 ++++ .../main/java/com/skyflow/logs/ErrorLogs.java | 185 ++++++ .../main/java/com/skyflow/logs/InfoLogs.java | 131 +++++ .../java/com/skyflow/logs/WarningLogs.java | 19 + .../serviceaccount/util/BearerToken.java | 26 +- .../util/SignedDataTokenResponse.java | 4 +- .../serviceaccount/util/SignedDataTokens.java | 14 +- .../skyflow/serviceaccount/util/Token.java | 0 .../java/com/skyflow/utils/BaseConstants.java | 34 ++ .../java/com/skyflow/utils/BaseUtils.java | 177 ++++++ .../java/com/skyflow/utils/SdkVersion.java | 13 + .../com/skyflow/utils/logger/LogUtil.java | 100 ++++ .../utils/validations/BaseValidations.java | 111 ++++ .../vault/controller/BaseVaultController.java | 21 + .../vault/controller/IVaultController.java | 9 + .../vault/data/BaseDetokenizeRequest.java | 4 + .../vault/data/BaseDetokenizeResponse.java | 4 + .../skyflow/vault/data/BaseInsertRequest.java | 4 + .../vault/data/BaseInsertResponse.java | 4 + flowvault/pom.xml | 128 +++++ .../src/main/java/com/skyflow/Skyflow.java | 144 +++++ .../main/java/com/skyflow/VaultClient.java | 73 +++ .../java/com/skyflow/config/Credentials.java | 9 + .../java/com/skyflow/config/VaultConfig.java | 33 ++ .../com/skyflow/enums/CustomHeaderKey.java | 18 + .../java/com/skyflow/enums/UpsertType.java | 18 + .../com/skyflow/generated/rest/ApiClient.java | 37 ++ .../generated/rest/ApiClientBuilder.java | 48 ++ .../generated/rest/AsyncApiClient.java | 37 ++ .../generated/rest/AsyncApiClientBuilder.java | 48 ++ .../rest/core/ApiClientApiException.java | 3 +- .../rest/core/ApiClientException.java | 0 .../rest/core/ApiClientHttpResponse.java | 3 +- .../generated/rest/core/ClientOptions.java | 171 ++++++ .../rest/core/DateTimeDeserializer.java | 1 + .../generated/rest/core/Environment.java | 20 + .../generated/rest/core/FileStream.java | 5 +- .../rest/core/InputStreamRequestBody.java | 7 +- .../generated/rest/core/MediaTypes.java | 0 .../skyflow/generated/rest/core/Nullable.java | 0 .../rest/core/NullableNonemptyFilter.java | 0 .../generated/rest/core/ObjectMappers.java | 1 + .../rest/core/QueryStringMapper.java | 7 +- .../generated/rest/core/RequestOptions.java | 87 +++ .../rest/core/ResponseBodyInputStream.java | 3 +- .../rest/core/ResponseBodyReader.java | 3 +- .../generated/rest/core/RetryInterceptor.java | 5 +- .../skyflow/generated/rest/core/Stream.java | 0 .../generated/rest/core/Suppliers.java | 0 .../flowservice/AsyncFlowserviceClient.java | 129 +++++ .../AsyncRawFlowserviceClient.java | 533 ++++++++++++++++++ .../flowservice/FlowserviceClient.java | 124 ++++ .../flowservice/RawFlowserviceClient.java | 412 ++++++++++++++ .../flowservice/requests/V1DeleteRequest.java | 186 ++++++ .../requests/V1FlowDeleteTokenRequest.java | 122 ++++ .../requests/V1FlowDetokenizeRequest.java | 156 +++++ .../requests/V1FlowTokenizeRequest.java | 125 ++++ .../requests/V1FlowVaultMetricsRequest.java | 96 ++++ .../flowservice/requests/V1GetRequest.java | 357 ++++++++++++ .../flowservice/requests/V1InsertRequest.java | 181 ++++++ .../flowservice/requests/V1UpdateRequest.java | 181 ++++++ .../records/AsyncRawRecordsClient.java | 96 ++++ .../resources/records/AsyncRecordsClient.java | 51 ++ .../resources/records/RawRecordsClient.java | 79 +++ .../rest/resources/records/RecordsClient.java | 49 ++ .../requests/V1ExecuteQueryRequest.java | 125 ++++ .../rest/types/FlowEnumUpdateType.java | 24 + .../FlowTokenizeResponseObjectToken.java | 188 ++++++ .../rest/types/GoogleprotobufAny.java | 146 +++++ .../generated/rest/types/RpcStatus.java | 135 +++++ .../rest/types/V1ColumnRedactions.java | 125 ++++ .../rest/types/V1DeleteResponse.java | 93 +++ .../rest/types/V1DeleteResponseObject.java | 156 +++++ .../types/V1DeleteTokenResponseObject.java | 156 +++++ .../types/V1ExecuteQueryRecordResponse.java | 96 ++++ .../rest/types/V1ExecuteQueryResponse.java | 118 ++++ .../types/V1ExecuteQueryResponseMetadata.java | 93 +++ .../rest/types/V1FlowDeleteTokenResponse.java | 94 +++ .../rest/types/V1FlowDetokenizeResponse.java | 94 +++ .../types/V1FlowDetokenizeResponseObject.java | 249 ++++++++ .../types/V1FlowTokenizeRequestObject.java | 153 +++++ .../rest/types/V1FlowTokenizeResponse.java | 94 +++ .../types/V1FlowTokenizeResponseObject.java | 124 ++++ .../rest/types/V1FlowVaultMetricsData.java | 96 ++++ .../types/V1FlowVaultMetricsResponse.java | 121 ++++ .../rest/types/V1GetRequestData.java | 216 +++++++ .../generated/rest/types/V1GetResponse.java | 93 +++ .../rest/types/V1InsertRecordData.java | 182 ++++++ .../rest/types/V1InsertResponse.java | 93 +++ .../rest/types/V1RecordResponseObject.java | 280 +++++++++ .../rest/types/V1TokenGroupRedactions.java | 125 ++++ .../generated/rest/types/V1UniqueValue.java | 96 ++++ .../rest/types/V1UpdateRecordData.java | 188 ++++++ .../rest/types/V1UpdateResponse.java | 93 +++ .../generated/rest/types/V1Upsert.java | 118 ++++ .../java/com/skyflow/utils/Constants.java | 49 ++ .../main/java/com/skyflow/utils/Utils.java | 111 ++++ .../utils/validations/Validations.java | 150 +++++ .../vault/controller/VaultController.java | 34 ++ .../skyflow/vault/data/DetokenizeRequest.java | 4 + .../vault/data/DetokenizeResponse.java | 4 + .../com/skyflow/vault/data/InsertRequest.java | 4 + .../skyflow/vault/data/InsertResponse.java | 4 + pom.xml | 113 +--- v2/pom.xml | 31 + .../java/com/skyflow/ConnectionClient.java | 0 .../src}/main/java/com/skyflow/Skyflow.java | 41 +- .../main/java/com/skyflow/VaultClient.java | 81 +-- .../com/skyflow/config/ConnectionConfig.java | 0 .../java/com/skyflow/config/Credentials.java | 10 + .../com/skyflow/config/ManagementConfig.java | 0 .../java/com/skyflow/config/VaultConfig.java | 16 + .../skyflow/enums/DeidentifyFileStatus.java | 0 .../com/skyflow/enums/DetectEntities.java | 0 .../enums/DetectOutputTranscriptions.java | 0 v2/src/main/java/com/skyflow/enums/Env.java | 8 + .../java/com/skyflow/enums/InterfaceName.java | 24 + .../main/java/com/skyflow/enums/LogLevel.java | 9 + .../java/com/skyflow/enums/MaskingMethod.java | 0 .../java/com/skyflow/enums/RedactionType.java | 0 .../java/com/skyflow/enums/RequestMethod.java | 0 .../java/com/skyflow/enums/TokenMode.java | 0 .../java/com/skyflow/enums/TokenType.java | 0 .../java/com/skyflow/errors/ErrorCode.java | 18 + .../java/com/skyflow/errors/ErrorMessage.java | 0 .../java/com/skyflow/errors/HttpStatus.java | 15 + .../com/skyflow/errors/SkyflowException.java | 0 .../com/skyflow/generated/rest/ApiClient.java | 2 + .../generated/rest/ApiClientBuilder.java | 0 .../generated/rest/AsyncApiClient.java | 2 + .../generated/rest/AsyncApiClientBuilder.java | 0 .../rest/core/ApiClientApiException.java | 74 +++ .../rest/core/ApiClientException.java | 17 + .../rest/core/ApiClientHttpResponse.java | 38 ++ .../generated/rest/core/ClientOptions.java | 3 +- .../rest/core/DateTimeDeserializer.java | 56 ++ .../generated/rest/core/Environment.java | 0 .../generated/rest/core/FileStream.java | 62 ++ .../rest/core/InputStreamRequestBody.java | 80 +++ .../generated/rest/core/MediaTypes.java | 13 + .../skyflow/generated/rest/core/Nullable.java | 140 +++++ .../rest/core/NullableNonemptyFilter.java | 19 + .../generated/rest/core/ObjectMappers.java | 38 ++ .../rest/core/QueryStringMapper.java | 139 +++++ .../generated/rest/core/RequestOptions.java | 0 .../rest/core/ResponseBodyInputStream.java | 46 ++ .../rest/core/ResponseBodyReader.java | 45 ++ .../generated/rest/core/RetryInterceptor.java | 79 +++ .../skyflow/generated/rest/core/Stream.java | 97 ++++ .../generated/rest/core/Suppliers.java | 23 + .../rest/errors/BadRequestError.java | 0 .../rest/errors/InternalServerError.java | 0 .../generated/rest/errors/NotFoundError.java | 0 .../rest/errors/UnauthorizedError.java | 0 .../resources/audit/AsyncAuditClient.java | 1 + .../resources/audit/AsyncRawAuditClient.java | 20 +- .../rest/resources/audit/AuditClient.java | 0 .../rest/resources/audit/RawAuditClient.java | 16 +- .../AuditServiceListAuditEventsRequest.java | 18 +- ...AuditEventsRequestFilterOpsActionType.java | 0 ...entsRequestFilterOpsContextAccessType.java | 0 ...ventsRequestFilterOpsContextActorType.java | 0 ...EventsRequestFilterOpsContextAuthMode.java | 0 ...ditEventsRequestFilterOpsResourceType.java | 0 ...eListAuditEventsRequestSortOpsOrderBy.java | 0 .../binlookup/AsyncBinLookupClient.java | 1 + .../binlookup/AsyncRawBinLookupClient.java | 21 +- .../resources/binlookup/BinLookupClient.java | 0 .../binlookup/RawBinLookupClient.java | 17 +- .../binlookup/requests/V1BinListRequest.java | 15 +- .../resources/files/AsyncFilesClient.java | 13 +- .../resources/files/AsyncRawFilesClient.java | 34 +- .../rest/resources/files/FilesClient.java | 12 +- .../rest/resources/files/RawFilesClient.java | 30 +- ...entifyFileAudioRequestDeidentifyAudio.java | 15 +- ...fyFileDocumentPdfRequestDeidentifyPdf.java | 15 +- ...entifyFileImageRequestDeidentifyImage.java | 15 +- .../files/requests/DeidentifyFileRequest.java | 15 +- ...identifyFileRequestDeidentifyDocument.java | 15 +- ...tifyFileRequestDeidentifyPresentation.java | 15 +- ...ntifyFileRequestDeidentifySpreadsheet.java | 15 +- ...fyFileRequestDeidentifyStructuredText.java | 15 +- .../DeidentifyFileRequestDeidentifyText.java | 15 +- .../files/requests/GetRunRequest.java | 9 +- .../ReidentifyFileRequestReidentifyFile.java | 11 +- ...RequestDeidentifyAudioEntityTypesItem.java | 0 ...estDeidentifyAudioOutputTranscription.java | 0 ...dfRequestDeidentifyPdfEntityTypesItem.java | 0 ...RequestDeidentifyImageEntityTypesItem.java | 0 ...geRequestDeidentifyImageMaskingMethod.java | 0 ...uestDeidentifyDocumentEntityTypesItem.java | 0 ...DeidentifyPresentationEntityTypesItem.java | 0 ...tDeidentifySpreadsheetEntityTypesItem.java | 0 ...identifyStructuredTextEntityTypesItem.java | 0 ...eRequestDeidentifyTextEntityTypesItem.java | 0 .../DeidentifyFileRequestEntityTypesItem.java | 0 .../guardrails/AsyncGuardrailsClient.java | 1 + .../guardrails/AsyncRawGuardrailsClient.java | 21 +- .../guardrails/GuardrailsClient.java | 0 .../guardrails/RawGuardrailsClient.java | 17 +- .../requests/DetectGuardrailsRequest.java | 15 +- .../resources/query/AsyncQueryClient.java | 1 + .../resources/query/AsyncRawQueryClient.java | 21 +- .../rest/resources/query/QueryClient.java | 0 .../rest/resources/query/RawQueryClient.java | 17 +- .../QueryServiceExecuteQueryBody.java | 9 +- .../records/AsyncRawRecordsClient.java | 45 +- .../resources/records/AsyncRecordsClient.java | 21 +- .../resources/records/RawRecordsClient.java | 41 +- .../rest/resources/records/RecordsClient.java | 22 +- .../FileServiceUploadFileRequest.java | 9 +- .../RecordServiceBatchOperationBody.java | 15 +- .../RecordServiceBulkDeleteRecordBody.java | 15 +- .../RecordServiceBulkGetRecordRequest.java | 16 +- .../RecordServiceGetRecordRequest.java | 16 +- .../RecordServiceInsertRecordBody.java | 15 +- .../RecordServiceUpdateRecordBody.java | 9 +- .../records/requests/UploadFileV2Request.java | 11 +- ...ordServiceBulkGetRecordRequestOrderBy.java | 0 ...dServiceBulkGetRecordRequestRedaction.java | 0 ...ecordServiceGetRecordRequestRedaction.java | 0 .../strings/AsyncRawStringsClient.java | 21 +- .../resources/strings/AsyncStringsClient.java | 1 + .../resources/strings/RawStringsClient.java | 17 +- .../rest/resources/strings/StringsClient.java | 0 .../requests/DeidentifyStringRequest.java | 15 +- .../requests/ReidentifyStringRequest.java | 9 +- ...eidentifyStringRequestEntityTypesItem.java | 0 .../tokens/AsyncRawTokensClient.java | 21 +- .../resources/tokens/AsyncTokensClient.java | 1 + .../resources/tokens/RawTokensClient.java | 17 +- .../rest/resources/tokens/TokensClient.java | 0 .../tokens/requests/V1DetokenizePayload.java | 15 +- .../tokens/requests/V1TokenizePayload.java | 15 +- .../types/AuditEventAuditResourceType.java | 0 .../rest/types/AuditEventContext.java | 9 +- .../generated/rest/types/AuditEventData.java | 9 +- .../rest/types/AuditEventHttpInfo.java | 9 +- .../rest/types/BatchRecordMethod.java | 0 .../rest/types/ContextAccessType.java | 0 .../generated/rest/types/ContextAuthMode.java | 0 .../rest/types/DeidentifiedFileOutput.java | 9 +- ...ifiedFileOutputProcessedFileExtension.java | 0 ...identifiedFileOutputProcessedFileType.java | 0 .../rest/types/DeidentifyFileResponse.java | 9 +- .../rest/types/DeidentifyStringResponse.java | 15 +- .../rest/types/DetectGuardrailsResponse.java | 11 +- .../DetectGuardrailsResponseValidation.java | 0 .../rest/types/DetectRunsResponse.java | 15 +- .../types/DetectRunsResponseOutputType.java | 0 .../rest/types/DetectRunsResponseStatus.java | 0 .../DetokenizeRecordResponseValueType.java | 0 .../generated/rest/types/ErrorResponse.java | 10 +- .../rest/types/ErrorResponseError.java | 15 +- .../generated/rest/types/FileData.java | 10 +- .../rest/types/FileDataDataFormat.java | 0 .../rest/types/FileDataDeidentifyAudio.java | 10 +- .../FileDataDeidentifyAudioDataFormat.java | 0 .../types/FileDataDeidentifyDocument.java | 10 +- .../FileDataDeidentifyDocumentDataFormat.java | 0 .../rest/types/FileDataDeidentifyImage.java | 10 +- .../FileDataDeidentifyImageDataFormat.java | 0 .../rest/types/FileDataDeidentifyPdf.java | 10 +- .../types/FileDataDeidentifyPresentation.java | 10 +- ...eDataDeidentifyPresentationDataFormat.java | 0 .../types/FileDataDeidentifySpreadsheet.java | 10 +- ...leDataDeidentifySpreadsheetDataFormat.java | 0 .../FileDataDeidentifyStructuredText.java | 10 +- ...ataDeidentifyStructuredTextDataFormat.java | 0 .../rest/types/FileDataDeidentifyText.java | 10 +- .../rest/types/FileDataReidentifyFile.java | 10 +- .../FileDataReidentifyFileDataFormat.java | 0 .../skyflow/generated/rest/types/Format.java | 15 +- .../rest/types/FormatMaskedItem.java | 0 .../rest/types/FormatPlaintextItem.java | 0 .../rest/types/FormatRedactedItem.java | 0 .../generated/rest/types/GooglerpcStatus.java | 15 +- .../rest/types/IdentifyResponse.java | 10 +- .../generated/rest/types/Locations.java | 9 +- .../generated/rest/types/ProtobufAny.java | 9 +- .../rest/types/RedactionEnumRedaction.java | 0 .../rest/types/ReidentifiedFileOutput.java | 9 +- ...ifiedFileOutputProcessedFileExtension.java | 0 .../rest/types/ReidentifyFileResponse.java | 9 +- .../ReidentifyFileResponseOutputType.java | 0 .../types/ReidentifyFileResponseStatus.java | 0 .../rest/types/RequestActionType.java | 0 .../generated/rest/types/ShiftDates.java | 15 +- .../rest/types/ShiftDatesEntityTypesItem.java | 0 .../rest/types/StringResponseEntities.java | 9 +- .../rest/types/TokenTypeMapping.java | 15 +- .../rest/types/TokenTypeMappingDefault.java | 0 .../types/TokenTypeMappingEntityOnlyItem.java | 0 .../TokenTypeMappingEntityUnqCounterItem.java | 0 .../types/TokenTypeMappingVaultTokenItem.java | 0 .../generated/rest/types/Transformations.java | 9 +- .../rest/types/UploadFileV2Response.java | 9 +- .../rest/types/V1AuditAfterOptions.java | 9 +- .../rest/types/V1AuditEventResponse.java | 9 +- .../generated/rest/types/V1AuditResponse.java | 15 +- .../rest/types/V1AuditResponseEvent.java | 15 +- .../types/V1AuditResponseEventRequest.java | 15 +- .../rest/types/V1BatchOperationResponse.java | 15 +- .../generated/rest/types/V1BatchRecord.java | 9 +- .../rest/types/V1BinListResponse.java | 15 +- .../types/V1BulkDeleteRecordResponse.java | 15 +- .../rest/types/V1BulkGetRecordResponse.java | 15 +- .../skyflow/generated/rest/types/V1Byot.java | 0 .../skyflow/generated/rest/types/V1Card.java | 9 +- .../rest/types/V1DeleteFileResponse.java | 9 +- .../rest/types/V1DeleteRecordResponse.java | 9 +- .../rest/types/V1DetokenizeRecordRequest.java | 9 +- .../types/V1DetokenizeRecordResponse.java | 9 +- .../rest/types/V1DetokenizeResponse.java | 15 +- .../generated/rest/types/V1FieldRecords.java | 9 +- .../rest/types/V1FileAvScanStatus.java | 0 .../rest/types/V1GetAuthTokenResponse.java | 9 +- .../types/V1GetFileScanStatusResponse.java | 9 +- .../rest/types/V1GetQueryResponse.java | 15 +- .../rest/types/V1InsertRecordResponse.java | 15 +- .../generated/rest/types/V1MemberType.java | 0 .../rest/types/V1RecordMetaProperties.java | 9 +- .../rest/types/V1TokenizeRecordRequest.java | 9 +- .../rest/types/V1TokenizeRecordResponse.java | 9 +- .../rest/types/V1TokenizeResponse.java | 15 +- .../rest/types/V1UpdateRecordResponse.java | 9 +- .../rest/types/V1VaultFieldMapping.java | 9 +- .../rest/types/V1VaultSchemaConfig.java | 9 +- .../rest/types/WordCharacterCount.java | 9 +- .../main/java/com/skyflow/logs/ErrorLogs.java | 0 .../main/java/com/skyflow/logs/InfoLogs.java | 0 .../java/com/skyflow/utils/Constants.java | 0 .../java/com/skyflow/utils/HttpUtility.java | 0 .../main/java/com/skyflow/utils/Utils.java | 0 .../com/skyflow/utils/logger/LogUtil.java | 0 .../utils/validations/Validations.java | 184 +++--- .../skyflow/vault/audit/ListEventRequest.java | 0 .../vault/audit/ListEventResponse.java | 0 .../com/skyflow/vault/bin/GetBinRequest.java | 0 .../com/skyflow/vault/bin/GetBinResponse.java | 0 .../connection/InvokeConnectionRequest.java | 0 .../connection/InvokeConnectionResponse.java | 0 .../vault/controller/AuditController.java | 0 .../vault/controller/BinLookupController.java | 0 .../controller/ConnectionController.java | 0 .../vault/controller/DetectController.java | 8 +- .../vault/controller/VaultController.java | 37 +- .../com/skyflow/vault/data/DeleteRequest.java | 0 .../skyflow/vault/data/DeleteResponse.java | 0 .../skyflow/vault/data/FileUploadRequest.java | 0 .../vault/data/FileUploadResponse.java | 0 .../com/skyflow/vault/data/GetRequest.java | 0 .../com/skyflow/vault/data/GetResponse.java | 0 .../com/skyflow/vault/data/InsertRequest.java | 0 .../skyflow/vault/data/InsertResponse.java | 0 .../com/skyflow/vault/data/QueryRequest.java | 0 .../com/skyflow/vault/data/QueryResponse.java | 0 .../com/skyflow/vault/data/UpdateRequest.java | 0 .../skyflow/vault/data/UpdateResponse.java | 0 .../com/skyflow/vault/detect/AudioBleep.java | 0 .../vault/detect/DateTransformation.java | 0 .../vault/detect/DeidentifyFileRequest.java | 0 .../vault/detect/DeidentifyFileResponse.java | 0 .../vault/detect/DeidentifyTextRequest.java | 0 .../vault/detect/DeidentifyTextResponse.java | 0 .../com/skyflow/vault/detect/EntityInfo.java | 0 .../skyflow/vault/detect/FileEntityInfo.java | 0 .../com/skyflow/vault/detect/FileInfo.java | 0 .../com/skyflow/vault/detect/FileInput.java | 0 .../vault/detect/GetDetectRunRequest.java | 0 .../vault/detect/ReidentifyTextRequest.java | 0 .../vault/detect/ReidentifyTextResponse.java | 0 .../com/skyflow/vault/detect/TextIndex.java | 0 .../com/skyflow/vault/detect/TokenFormat.java | 0 .../skyflow/vault/detect/Transformations.java | 0 .../com/skyflow/vault/tokens/ColumnValue.java | 0 .../skyflow/vault/tokens/DetokenizeData.java | 0 .../tokens/DetokenizeRecordResponse.java | 0 .../vault/tokens/DetokenizeRequest.java | 0 .../vault/tokens/DetokenizeResponse.java | 0 .../skyflow/vault/tokens/TokenizeRequest.java | 0 .../vault/tokens/TokenizeResponse.java | 0 {src => v2/src}/main/resources/sdk.properties | 0 .../skyflow/ConnectionClientDotenvTests.java | 0 .../com/skyflow/ConnectionClientTests.java | 0 .../test/java/com/skyflow/SkyflowTests.java | 56 +- .../com/skyflow/VaultClientDotenvTests.java | 1 + .../java/com/skyflow/VaultClientTests.java | 7 +- .../skyflow/config/ConnectionConfigTests.java | 0 .../com/skyflow/config/CredentialsTests.java | 0 .../skyflow/config/ManagementConfigTest.java | 0 .../com/skyflow/config/VaultConfigTests.java | 16 +- .../enums/DeidentifyFileStatusTest.java | 0 .../com/skyflow/enums/DetectEntitiesTest.java | 0 .../enums/DetectOutputTranscriptionsTest.java | 0 .../com/skyflow/enums/MaskingMethodTest.java | 0 .../java/com/skyflow/enums/TokenModeTest.java | 1 - .../java/com/skyflow/enums/TokenTypeTest.java | 0 .../skyflow/errors/SkyflowExceptionTest.java | 0 .../serviceaccount/util/BearerTokenTests.java | 0 .../util/SignedDataTokensTests.java | 0 .../serviceaccount/util/TokenTests.java | 0 .../com/skyflow/utils/HttpUtilityTests.java | 0 .../java/com/skyflow/utils/UtilsTests.java | 0 .../utils/logger/LogUtilLevelTests.java | 0 .../java/com/skyflow/vault/BinAuditTests.java | 0 .../connection/InvokeConnectionTests.java | 0 .../controller/ConnectionControllerTests.java | 1 - .../controller/DetectControllerFileTests.java | 1 + .../controller/DetectControllerTests.java | 9 +- .../controller/VaultControllerTests.java | 0 .../com/skyflow/vault/data/DeleteTests.java | 5 +- .../skyflow/vault/data/FileUploadTests.java | 0 .../java/com/skyflow/vault/data/GetTests.java | 5 +- .../com/skyflow/vault/data/InsertTests.java | 5 +- .../skyflow/vault/data/QueryResponseTest.java | 0 .../com/skyflow/vault/data/QueryTests.java | 5 +- .../com/skyflow/vault/data/UpdateTests.java | 5 +- .../detect/DeidentifyFileRequestTest.java | 0 .../detect/DeidentifyFileResponseTest.java | 0 .../vault/detect/DeidentifyTextTests.java | 0 .../vault/detect/FileEntityInfoTest.java | 0 .../skyflow/vault/detect/FileInfoTest.java | 0 .../vault/detect/ReidentifyTextTests.java | 0 .../skyflow/vault/tokens/DetokenizeTests.java | 0 .../skyflow/vault/tokens/TokenizeTests.java | 7 +- .../invalidPrivateKeyCredentials.json | 0 .../resources/invalidTokenURICredentials.json | 0 .../test/resources/noClientIDCredentials.json | 0 .../test/resources/noKeyIDCredentials.json | 0 .../resources/noPrivateKeyCredentials.json | 0 .../test/resources/noTokenURICredentials.json | 0 {src => v2/src}/test/resources/notJson.txt | 0 477 files changed, 12823 insertions(+), 1703 deletions(-) create mode 100644 common/pom.xml create mode 100644 common/src/main/java/com/skyflow/BaseSkyflow.java create mode 100644 common/src/main/java/com/skyflow/BaseVaultClient.java rename src/main/java/com/skyflow/config/Credentials.java => common/src/main/java/com/skyflow/config/BaseCredentials.java (87%) rename src/main/java/com/skyflow/config/VaultConfig.java => common/src/main/java/com/skyflow/config/BaseVaultConfig.java (70%) rename {src => common/src}/main/java/com/skyflow/enums/Env.java (100%) rename {src => common/src}/main/java/com/skyflow/enums/InterfaceName.java (100%) rename {src => common/src}/main/java/com/skyflow/enums/LogLevel.java (100%) rename {src => common/src}/main/java/com/skyflow/errors/ErrorCode.java (100%) create mode 100644 common/src/main/java/com/skyflow/errors/ErrorMessage.java rename {src => common/src}/main/java/com/skyflow/errors/HttpStatus.java (100%) create mode 100644 common/src/main/java/com/skyflow/errors/SkyflowException.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientApiException.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientException.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientHttpResponse.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/DateTimeDeserializer.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/Environment.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/FileStream.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/InputStreamRequestBody.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/MediaTypes.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/Nullable.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/NullableNonemptyFilter.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/ObjectMappers.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/QueryStringMapper.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/RequestOptions.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyInputStream.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyReader.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/core/Suppliers.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/errors/BadRequestError.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/errors/NotFoundError.java create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/errors/UnauthorizedError.java rename {src/main/java/com/skyflow/generated => common/src/main/java/com/skyflow/generated/auth}/rest/resources/authentication/AsyncAuthenticationClient.java (84%) rename {src/main/java/com/skyflow/generated => common/src/main/java/com/skyflow/generated/auth}/rest/resources/authentication/AsyncRawAuthenticationClient.java (82%) rename {src/main/java/com/skyflow/generated => common/src/main/java/com/skyflow/generated/auth}/rest/resources/authentication/AuthenticationClient.java (82%) rename {src/main/java/com/skyflow/generated => common/src/main/java/com/skyflow/generated/auth}/rest/resources/authentication/RawAuthenticationClient.java (78%) rename {src/main/java/com/skyflow/generated => common/src/main/java/com/skyflow/generated/auth}/rest/resources/authentication/requests/V1GetAuthTokenRequest.java (96%) create mode 100644 common/src/main/java/com/skyflow/generated/auth/rest/types/V1GetAuthTokenResponse.java create mode 100644 common/src/main/java/com/skyflow/logs/ErrorLogs.java create mode 100644 common/src/main/java/com/skyflow/logs/InfoLogs.java create mode 100644 common/src/main/java/com/skyflow/logs/WarningLogs.java rename {src => common/src}/main/java/com/skyflow/serviceaccount/util/BearerToken.java (92%) rename {src => common/src}/main/java/com/skyflow/serviceaccount/util/SignedDataTokenResponse.java (83%) rename {src => common/src}/main/java/com/skyflow/serviceaccount/util/SignedDataTokens.java (97%) rename {src => common/src}/main/java/com/skyflow/serviceaccount/util/Token.java (100%) create mode 100644 common/src/main/java/com/skyflow/utils/BaseConstants.java create mode 100644 common/src/main/java/com/skyflow/utils/BaseUtils.java create mode 100644 common/src/main/java/com/skyflow/utils/SdkVersion.java create mode 100644 common/src/main/java/com/skyflow/utils/logger/LogUtil.java create mode 100644 common/src/main/java/com/skyflow/utils/validations/BaseValidations.java create mode 100644 common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java create mode 100644 common/src/main/java/com/skyflow/vault/controller/IVaultController.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRequest.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java create mode 100644 flowvault/pom.xml create mode 100644 flowvault/src/main/java/com/skyflow/Skyflow.java create mode 100644 flowvault/src/main/java/com/skyflow/VaultClient.java create mode 100644 flowvault/src/main/java/com/skyflow/config/Credentials.java create mode 100644 flowvault/src/main/java/com/skyflow/config/VaultConfig.java create mode 100644 flowvault/src/main/java/com/skyflow/enums/CustomHeaderKey.java create mode 100644 flowvault/src/main/java/com/skyflow/enums/UpsertType.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java (99%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/ApiClientException.java (100%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java (99%) create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java (99%) create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/FileStream.java (99%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java (99%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/MediaTypes.java (100%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/Nullable.java (100%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java (100%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/ObjectMappers.java (99%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java (97%) create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java (99%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java (99%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java (99%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/Stream.java (100%) rename {src => flowvault/src}/main/java/com/skyflow/generated/rest/core/Suppliers.java (100%) create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncFlowserviceClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncRawFlowserviceClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/FlowserviceClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/RawFlowserviceClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1DeleteRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDeleteTokenRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDetokenizeRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowTokenizeRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowVaultMetricsRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1GetRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1InsertRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1UpdateRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/V1ExecuteQueryRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/FlowEnumUpdateType.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/FlowTokenizeResponseObjectToken.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleprotobufAny.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/RpcStatus.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1ColumnRedactions.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponseObject.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteTokenResponseObject.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryRecordResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponseMetadata.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDeleteTokenResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponseObject.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeRequestObject.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponseObject.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsData.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetRequestData.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordData.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1RecordResponseObject.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1TokenGroupRedactions.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1UniqueValue.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordData.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/generated/rest/types/V1Upsert.java create mode 100644 flowvault/src/main/java/com/skyflow/utils/Constants.java create mode 100644 flowvault/src/main/java/com/skyflow/utils/Utils.java create mode 100644 flowvault/src/main/java/com/skyflow/utils/validations/Validations.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java create mode 100644 v2/pom.xml rename {src => v2/src}/main/java/com/skyflow/ConnectionClient.java (100%) rename {src => v2/src}/main/java/com/skyflow/Skyflow.java (96%) rename {src => v2/src}/main/java/com/skyflow/VaultClient.java (92%) rename {src => v2/src}/main/java/com/skyflow/config/ConnectionConfig.java (100%) create mode 100644 v2/src/main/java/com/skyflow/config/Credentials.java rename {src => v2/src}/main/java/com/skyflow/config/ManagementConfig.java (100%) create mode 100644 v2/src/main/java/com/skyflow/config/VaultConfig.java rename {src => v2/src}/main/java/com/skyflow/enums/DeidentifyFileStatus.java (100%) rename {src => v2/src}/main/java/com/skyflow/enums/DetectEntities.java (100%) rename {src => v2/src}/main/java/com/skyflow/enums/DetectOutputTranscriptions.java (100%) create mode 100644 v2/src/main/java/com/skyflow/enums/Env.java create mode 100644 v2/src/main/java/com/skyflow/enums/InterfaceName.java create mode 100644 v2/src/main/java/com/skyflow/enums/LogLevel.java rename {src => v2/src}/main/java/com/skyflow/enums/MaskingMethod.java (100%) rename {src => v2/src}/main/java/com/skyflow/enums/RedactionType.java (100%) rename {src => v2/src}/main/java/com/skyflow/enums/RequestMethod.java (100%) rename {src => v2/src}/main/java/com/skyflow/enums/TokenMode.java (100%) rename {src => v2/src}/main/java/com/skyflow/enums/TokenType.java (100%) create mode 100644 v2/src/main/java/com/skyflow/errors/ErrorCode.java rename {src => v2/src}/main/java/com/skyflow/errors/ErrorMessage.java (100%) create mode 100644 v2/src/main/java/com/skyflow/errors/HttpStatus.java rename {src => v2/src}/main/java/com/skyflow/errors/SkyflowException.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/ApiClient.java (98%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/ApiClientBuilder.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/AsyncApiClient.java (98%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java (100%) create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/ApiClientException.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java rename {src => v2/src}/main/java/com/skyflow/generated/rest/core/ClientOptions.java (99%) create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java rename {src => v2/src}/main/java/com/skyflow/generated/rest/core/Environment.java (100%) create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/MediaTypes.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/Nullable.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java rename {src => v2/src}/main/java/com/skyflow/generated/rest/core/RequestOptions.java (100%) create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/Stream.java create mode 100644 v2/src/main/java/com/skyflow/generated/rest/core/Suppliers.java rename {src => v2/src}/main/java/com/skyflow/generated/rest/errors/BadRequestError.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/errors/InternalServerError.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/errors/NotFoundError.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/AsyncAuditClient.java (99%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java (95%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/AuditClient.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java (95%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java (98%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsActionType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAccessType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextActorType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAuthMode.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsResourceType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestSortOpsOrderBy.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncBinLookupClient.java (99%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java (88%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/binlookup/BinLookupClient.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java (87%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java (96%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java (96%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java (98%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java (86%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageMaskingMethod.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyDocumentEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyPresentationEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyTextEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncGuardrailsClient.java (99%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java (89%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/guardrails/GuardrailsClient.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java (87%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java (99%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java (94%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java (96%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java (95%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java (88%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java (85%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java (96%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java (95%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestOrderBy.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestRedaction.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceGetRecordRequestRedaction.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java (94%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/strings/AsyncStringsClient.java (99%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/strings/StringsClient.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/strings/types/DeidentifyStringRequestEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java (94%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java (99%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java (85%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/AuditEventAuditResourceType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/AuditEventContext.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/AuditEventData.java (87%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java (89%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/BatchRecordMethod.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ContextAccessType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ContextAuthMode.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileExtension.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java (87%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java (94%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponseValidation.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java (95%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DetectRunsResponseOutputType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DetectRunsResponseStatus.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/DetokenizeRecordResponseValueType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ErrorResponse.java (88%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileData.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudioDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocumentDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImageDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentationDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheetDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredTextDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFileDataFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/Format.java (89%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FormatMaskedItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FormatPlaintextItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/FormatRedactedItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java (88%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java (89%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/Locations.java (94%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ProtobufAny.java (86%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/RedactionEnumRedaction.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutputProcessedFileExtension.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseOutputType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseStatus.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/RequestActionType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ShiftDates.java (89%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/ShiftDatesEntityTypesItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java (94%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/TokenTypeMappingDefault.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityOnlyItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityUnqCounterItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/TokenTypeMappingVaultTokenItem.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/Transformations.java (87%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java (86%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java (95%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java (89%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java (97%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java (83%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java (85%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java (83%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1Byot.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1Card.java (96%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java (93%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java (84%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1FileAvScanStatus.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java (87%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java (83%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java (84%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1MemberType.java (100%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java (87%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java (84%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java (90%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java (92%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java (91%) rename {src => v2/src}/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java (90%) rename {src => v2/src}/main/java/com/skyflow/logs/ErrorLogs.java (100%) rename {src => v2/src}/main/java/com/skyflow/logs/InfoLogs.java (100%) rename {src => v2/src}/main/java/com/skyflow/utils/Constants.java (100%) rename {src => v2/src}/main/java/com/skyflow/utils/HttpUtility.java (100%) rename {src => v2/src}/main/java/com/skyflow/utils/Utils.java (100%) rename {src => v2/src}/main/java/com/skyflow/utils/logger/LogUtil.java (100%) rename {src => v2/src}/main/java/com/skyflow/utils/validations/Validations.java (99%) rename {src => v2/src}/main/java/com/skyflow/vault/audit/ListEventRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/audit/ListEventResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/bin/GetBinRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/bin/GetBinResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/connection/InvokeConnectionRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/controller/AuditController.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/controller/BinLookupController.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/controller/ConnectionController.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/controller/DetectController.java (99%) rename {src => v2/src}/main/java/com/skyflow/vault/controller/VaultController.java (92%) rename {src => v2/src}/main/java/com/skyflow/vault/data/DeleteRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/DeleteResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/FileUploadRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/FileUploadResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/GetRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/GetResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/InsertRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/InsertResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/QueryRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/QueryResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/UpdateRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/data/UpdateResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/AudioBleep.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/DateTransformation.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/DeidentifyTextRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/DeidentifyTextResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/EntityInfo.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/FileEntityInfo.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/FileInfo.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/FileInput.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/ReidentifyTextRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/ReidentifyTextResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/TextIndex.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/TokenFormat.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/detect/Transformations.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/tokens/ColumnValue.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/tokens/DetokenizeData.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/tokens/DetokenizeResponse.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/tokens/TokenizeRequest.java (100%) rename {src => v2/src}/main/java/com/skyflow/vault/tokens/TokenizeResponse.java (100%) rename {src => v2/src}/main/resources/sdk.properties (100%) rename {src => v2/src}/test/java/com/skyflow/ConnectionClientDotenvTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/ConnectionClientTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/SkyflowTests.java (94%) rename {src => v2/src}/test/java/com/skyflow/VaultClientDotenvTests.java (98%) rename {src => v2/src}/test/java/com/skyflow/VaultClientTests.java (99%) rename {src => v2/src}/test/java/com/skyflow/config/ConnectionConfigTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/config/CredentialsTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/config/ManagementConfigTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/config/VaultConfigTests.java (91%) rename {src => v2/src}/test/java/com/skyflow/enums/DeidentifyFileStatusTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/enums/DetectEntitiesTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/enums/DetectOutputTranscriptionsTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/enums/MaskingMethodTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/enums/TokenModeTest.java (98%) rename {src => v2/src}/test/java/com/skyflow/enums/TokenTypeTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/errors/SkyflowExceptionTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/serviceaccount/util/TokenTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/utils/HttpUtilityTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/utils/UtilsTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/BinAuditTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java (99%) rename {src => v2/src}/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java (99%) rename {src => v2/src}/test/java/com/skyflow/vault/controller/DetectControllerTests.java (99%) rename {src => v2/src}/test/java/com/skyflow/vault/controller/VaultControllerTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/data/DeleteTests.java (97%) rename {src => v2/src}/test/java/com/skyflow/vault/data/FileUploadTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/data/GetTests.java (99%) rename {src => v2/src}/test/java/com/skyflow/vault/data/InsertTests.java (99%) rename {src => v2/src}/test/java/com/skyflow/vault/data/QueryResponseTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/data/QueryTests.java (96%) rename {src => v2/src}/test/java/com/skyflow/vault/data/UpdateTests.java (99%) rename {src => v2/src}/test/java/com/skyflow/vault/detect/DeidentifyFileRequestTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/detect/DeidentifyFileResponseTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/detect/DeidentifyTextTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/detect/FileEntityInfoTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/detect/FileInfoTest.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/detect/ReidentifyTextTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/tokens/DetokenizeTests.java (100%) rename {src => v2/src}/test/java/com/skyflow/vault/tokens/TokenizeTests.java (97%) rename {src => v2/src}/test/resources/invalidPrivateKeyCredentials.json (100%) rename {src => v2/src}/test/resources/invalidTokenURICredentials.json (100%) rename {src => v2/src}/test/resources/noClientIDCredentials.json (100%) rename {src => v2/src}/test/resources/noKeyIDCredentials.json (100%) rename {src => v2/src}/test/resources/noPrivateKeyCredentials.json (100%) rename {src => v2/src}/test/resources/noTokenURICredentials.json (100%) rename {src => v2/src}/test/resources/notJson.txt (100%) diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 00000000..72fff275 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + com.skyflow + skyflow + 1.0.0 + ../pom.xml + + + common + 1.0.0 + ${project.groupId}:${project.artifactId} + + + + true + 8 + 8 + UTF-8 + + \ No newline at end of file diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java new file mode 100644 index 00000000..83e31c1e --- /dev/null +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -0,0 +1,36 @@ +package com.skyflow; + +import com.skyflow.enums.LogLevel; +import com.skyflow.logs.InfoLogs; +import com.skyflow.utils.BaseUtils; +import com.skyflow.utils.logger.LogUtil; + +class BaseSkyflow { + private final BaseSkyflowClientBuilder builder; + + protected BaseSkyflow(BaseSkyflowClientBuilder builder) { + this.builder = builder; + LogUtil.printInfoLog(InfoLogs.CLIENT_INITIALIZED.getLog()); + } + + public LogLevel getLogLevel() { + return this.builder.logLevel; + } + + static class BaseSkyflowClientBuilder { + protected LogLevel logLevel = LogLevel.ERROR; + + protected BaseSkyflowClientBuilder() { + } + + protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { + this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel; + LogUtil.setupLogger(this.logLevel); + LogUtil.printInfoLog(BaseUtils.parameterizedString( + InfoLogs.CURRENT_LOG_LEVEL.getLog(), String.valueOf(this.logLevel) + )); + return this; + } + } + +} diff --git a/common/src/main/java/com/skyflow/BaseVaultClient.java b/common/src/main/java/com/skyflow/BaseVaultClient.java new file mode 100644 index 00000000..f0ea23d1 --- /dev/null +++ b/common/src/main/java/com/skyflow/BaseVaultClient.java @@ -0,0 +1,93 @@ +package com.skyflow; + +import com.skyflow.config.BaseCredentials; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.InfoLogs; +import com.skyflow.serviceaccount.util.Token; +import com.skyflow.utils.BaseConstants; +import com.skyflow.utils.BaseUtils; +import com.skyflow.utils.logger.LogUtil; +import com.skyflow.utils.validations.BaseValidations; +import io.github.cdimascio.dotenv.Dotenv; +import io.github.cdimascio.dotenv.DotenvException; +import okhttp3.ConnectionPool; +import okhttp3.OkHttpClient; +import okhttp3.Request; + +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +class BaseVaultClient { + protected OkHttpClient sharedHttpClient; + protected String currentVaultURL; + protected BaseCredentials commonCredentials; + protected BaseCredentials finalCredentials; + protected String token; + protected String apiKey; + + public BaseVaultClient() { + } + + protected OkHttpClient buildSharedHttpClient(Supplier tokenSupplier) { + return new OkHttpClient.Builder() + .connectionPool(new ConnectionPool(10, 1, TimeUnit.MINUTES)) + .addInterceptor(chain -> { + Request requestWithAuth = chain.request().newBuilder() + .header("Authorization", "Bearer " + tokenSupplier.get()) + .build(); + return chain.proceed(requestWithAuth); + }) + .build(); + } + + protected void prioritiseCredentials(BaseCredentials vaultSpecificCredentials) throws SkyflowException { + try { + BaseCredentials original = this.finalCredentials; + if (vaultSpecificCredentials != null) { + this.finalCredentials = vaultSpecificCredentials; + } else if (this.commonCredentials != null) { + this.finalCredentials = this.commonCredentials; + } else { + String sysCredentials = System.getenv(BaseConstants.ENV_CREDENTIALS_KEY_NAME); + if (sysCredentials == null) { + Dotenv dotenv = Dotenv.load(); + sysCredentials = dotenv.get(BaseConstants.ENV_CREDENTIALS_KEY_NAME); + } + if (sysCredentials == null) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentials.getMessage()); + } else { + this.finalCredentials = new BaseCredentials(); + this.finalCredentials.setCredentialsString(sysCredentials); + } + } + if (original != null && !original.equals(this.finalCredentials)) { + token = null; + apiKey = null; + } + } catch (DotenvException e) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentials.getMessage()); + } catch (SkyflowException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected void setBearerToken(BaseCredentials vaultSpecificCredentials) throws SkyflowException { + prioritiseCredentials(vaultSpecificCredentials); + BaseValidations.validateCredentials(this.finalCredentials); + if (this.finalCredentials.getApiKey() != null) { + LogUtil.printInfoLog(InfoLogs.USE_API_KEY.getLog()); + token = this.finalCredentials.getApiKey(); + } else if (token == null || token.trim().isEmpty()) { + token = BaseUtils.generateBearerToken(this.finalCredentials); + } else if (Token.isExpired(token)) { + LogUtil.printInfoLog(InfoLogs.BEARER_TOKEN_EXPIRED.getLog()); + token = BaseUtils.generateBearerToken(this.finalCredentials); + } else { + LogUtil.printInfoLog(InfoLogs.REUSE_BEARER_TOKEN.getLog()); + } + } +} diff --git a/src/main/java/com/skyflow/config/Credentials.java b/common/src/main/java/com/skyflow/config/BaseCredentials.java similarity index 87% rename from src/main/java/com/skyflow/config/Credentials.java rename to common/src/main/java/com/skyflow/config/BaseCredentials.java index c2594ef6..34b2c117 100644 --- a/src/main/java/com/skyflow/config/Credentials.java +++ b/common/src/main/java/com/skyflow/config/BaseCredentials.java @@ -3,18 +3,18 @@ import java.util.ArrayList; import java.util.Map; -public class Credentials { +public class BaseCredentials implements Cloneable { private String path; private ArrayList roles; - private Object context; private String credentialsString; private String token; private String apiKey; + private Object context; - public Credentials() { + public BaseCredentials() { this.path = null; - this.context = null; this.credentialsString = null; + this.context = null; } public String getPath() { @@ -33,18 +33,6 @@ public void setRoles(ArrayList roles) { this.roles = roles; } - public Object getContext() { - return context; - } - - public void setContext(String context) { - this.context = context; - } - - public void setContext(Map context) { - this.context = context; - } - public String getCredentialsString() { return credentialsString; } @@ -68,4 +56,20 @@ public String getApiKey() { public void setApiKey(String apiKey) { this.apiKey = apiKey; } + public Object getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public void setContext(Map context) { + this.context = context; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } } diff --git a/src/main/java/com/skyflow/config/VaultConfig.java b/common/src/main/java/com/skyflow/config/BaseVaultConfig.java similarity index 70% rename from src/main/java/com/skyflow/config/VaultConfig.java rename to common/src/main/java/com/skyflow/config/BaseVaultConfig.java index 4f61af2a..e59aeb91 100644 --- a/src/main/java/com/skyflow/config/VaultConfig.java +++ b/common/src/main/java/com/skyflow/config/BaseVaultConfig.java @@ -2,17 +2,17 @@ import com.skyflow.enums.Env; -public class VaultConfig { +public class BaseVaultConfig { private String vaultId; private String clusterId; + private String vaultURL; private Env env; - private Credentials credentials; - public VaultConfig() { + public BaseVaultConfig() { this.vaultId = null; this.clusterId = null; + this.vaultURL = null; this.env = Env.PROD; - this.credentials = null; } public String getVaultId() { @@ -39,11 +39,13 @@ public void setEnv(Env env) { this.env = env == null ? Env.PROD : env; } - public Credentials getCredentials() { - return credentials; + + public String getVaultURL() { + return vaultURL; } - public void setCredentials(Credentials credentials) { - this.credentials = credentials; + public void setVaultURL(String vaultURL) { + this.vaultURL = vaultURL; } + } diff --git a/src/main/java/com/skyflow/enums/Env.java b/common/src/main/java/com/skyflow/enums/Env.java similarity index 100% rename from src/main/java/com/skyflow/enums/Env.java rename to common/src/main/java/com/skyflow/enums/Env.java diff --git a/src/main/java/com/skyflow/enums/InterfaceName.java b/common/src/main/java/com/skyflow/enums/InterfaceName.java similarity index 100% rename from src/main/java/com/skyflow/enums/InterfaceName.java rename to common/src/main/java/com/skyflow/enums/InterfaceName.java diff --git a/src/main/java/com/skyflow/enums/LogLevel.java b/common/src/main/java/com/skyflow/enums/LogLevel.java similarity index 100% rename from src/main/java/com/skyflow/enums/LogLevel.java rename to common/src/main/java/com/skyflow/enums/LogLevel.java diff --git a/src/main/java/com/skyflow/errors/ErrorCode.java b/common/src/main/java/com/skyflow/errors/ErrorCode.java similarity index 100% rename from src/main/java/com/skyflow/errors/ErrorCode.java rename to common/src/main/java/com/skyflow/errors/ErrorCode.java diff --git a/common/src/main/java/com/skyflow/errors/ErrorMessage.java b/common/src/main/java/com/skyflow/errors/ErrorMessage.java new file mode 100644 index 00000000..169880e9 --- /dev/null +++ b/common/src/main/java/com/skyflow/errors/ErrorMessage.java @@ -0,0 +1,210 @@ +package com.skyflow.errors; + +import com.skyflow.utils.SdkVersion; + +public enum ErrorMessage { + // Client initialization + VaultIdAlreadyInConfigList("%s0 Validation error. VaultId is present in an existing config. Specify a new vaultId in config."), + VaultIdNotInConfigList("%s0 Validation error. VaultId is missing from the config. Specify the vaultIds from configs."), + OnlySingleVaultConfigAllowed("%s0 Validation error. A vault config already exists. Cannot add another vault config."), + ConnectionIdAlreadyInConfigList("%s0 Validation error. ConnectionId is present in an existing config. Specify a connectionId in config."), + ConnectionIdNotInConfigList("%s0 Validation error. ConnectionId is missing from the config. Specify the connectionIds from configs."), + EmptyCredentials("%s0 Validation error. Invalid credentials. Credentials must not be empty."), + TableSpecifiedInRequestAndRecordObject("%s0 Validation error. Table name cannot be specified at both the request and record levels. Please specify the table name in only one place."), + UpsertTableRequestAtRecordLevel("%s0 Validation error. Table name should be present at each record level when upsert is present at record level."), + UpsertTableRequestAtRequestLevel("%s0 Validation error. Upsert should be present at each record level when table name is present at record level."), + TableNotSpecifiedInRequestAndRecordObject("%s0 Validation error. Table name is missing. Table name should be specified at one place either at the request level or record level. Please specify the table name at one place."), + // Vault config + InvalidVaultId("%s0 Initialization failed. Invalid vault ID. Specify a valid vault ID."), + EmptyVaultId("%s0 Initialization failed. Invalid vault ID. Vault ID must not be empty."), + InvalidClusterId("%s0 Initialization failed. Invalid cluster ID. Specify cluster ID."), + EmptyClusterId("%s0 Initialization failed. Invalid cluster ID. Specify a valid cluster ID."), + EmptyVaultUrl("%s0 Initialization failed. Vault URL is empty. Specify a valid vault URL."), + InvalidVaultUrlFormat("%s0 Initialization failed. Vault URL must start with 'https://'."), + EitherVaultUrlOrClusterIdRequired("%s0 Initialization failed. Specify either 'clusterId' or 'vaultURL'."), + + // Connection config + InvalidConnectionId("%s0 Initialization failed. Invalid connection ID. Specify a valid connection ID."), + EmptyConnectionId("%s0 Initialization failed. Invalid connection ID. Connection ID must not be empty."), + InvalidConnectionUrl("%s0 Initialization failed. Invalid connection URL. Specify a valid connection URL."), + EmptyConnectionUrl("%s0 Initialization failed. Invalid connection URL. Connection URL must not be empty."), + InvalidConnectionUrlFormat("%s0 Initialization failed. Connection URL is not a valid URL. Specify a valid connection URL."), + + // Credentials + MultipleTokenGenerationMeansPassed("%s0 Initialization failed. Invalid credentials. Specify only one from 'path', 'credentialsString', 'token' or 'apiKey'."), + NoTokenGenerationMeansPassed("%s0 Initialization failed. Invalid credentials. Specify any one from 'path', 'credentialsString', 'token' or 'apiKey'."), + EmptyCredentialFilePath("%s0 Initialization failed. Invalid credentials. Credentials file path must not be empty."), + EmptyCredentialsString("%s0 Initialization failed. Invalid credentials. Credentials string must not be empty."), + EmptyToken("%s0 Initialization failed. Invalid credentials. Token must not be empty."), + EmptyApikey("%s0 Initialization failed. Invalid credentials. Api key must not be empty."), + InvalidApikey("%s0 Initialization failed. Invalid credentials. Specify valid api key."), + EmptyRoles("%s0 Initialization failed. Invalid roles. Specify at least one role."), + EmptyRoleInRoles("%s0 Initialization failed. Invalid role. Specify a valid role."), + EmptyContext("%s0 Initialization failed. Invalid context. Specify a valid context."), + InvalidContextType("%s0 Initialization failed. Invalid context type. Specify context as a String or Map."), + InvalidContextMapKey("%s0 Initialization failed. Invalid key '%s1' in context map. Keys must contain only alphanumeric characters and underscores."), + + // Bearer token generation + FileNotFound("%s0 Initialization failed. Credential file not found at %s1. Verify the file path."), + FileInvalidJson("%s0 Initialization failed. File at %s1 is not in valid JSON format. Verify the file contents."), + CredentialsStringInvalidJson("%s0 Initialization failed. Credentials string is not in valid JSON format. Verify the credentials string contents."), + InvalidCredentials("%s0 Initialization failed. Invalid credentials provided. Specify valid credentials."), + MissingPrivateKey("%s0 Initialization failed. Unable to read private key in credentials. Verify your private key."), + MissingClientId("%s0 Initialization failed. Unable to read client ID in credentials. Verify your client ID."), + MissingKeyId("%s0 Initialization failed. Unable to read key ID in credentials. Verify your key ID."), + MissingTokenUri("%s0 Initialization failed. Unable to read token URI in credentials. Verify your token URI."), + InvalidTokenUri("%s0 Initialization failed. Token URI in not a valid URL in credentials. Verify your token URI."), + JwtInvalidFormat("%s0 Initialization failed. Invalid private key format. Verify your credentials."), + InvalidAlgorithm("%s0 Initialization failed. Invalid algorithm to parse private key. Specify valid algorithm."), + InvalidKeySpec("%s0 Initialization failed. Unable to parse RSA private key. Verify your credentials."), + JwtDecodeError("%s0 Validation error. Invalid access token. Verify your credentials."), + MissingAccessToken("%s0 Validation error. Access token not present in the response from bearer token generation. Verify your credentials."), + MissingTokenType("%s0 Validation error. Token type not present in the response from bearer token generation. Verify your credentials."), + BearerTokenExpired("%s0 Validation error. Bearer token is invalid or expired. Please provide a valid bearer token."), + + // Insert + TableKeyError("%s0 Validation error. 'table' key is missing from the payload. Specify a 'table' key."), + EmptyTable("%s0 Validation error. 'table' can't be empty. Specify a table."), + ValuesKeyError("%s0 Validation error. 'values' key is missing from the payload. Specify a 'values' key."), + EmptyRecords("%s0 Validation error. 'records' can't be empty. Specify records."), + EmptyKeyInRecords("%s0 Validation error. Invalid key in data in records. Specify a valid key."), + EmptyValueInRecords("%s0 Validation error. Invalid value in records. Specify a valid value."), + RecordsKeyError("%s0 Validation error. 'records' key is missing from the payload. Specify a 'records' key."), + EmptyValues("%s0 Validation error. 'values' can't be empty. Specify values."), + EmptyKeyInValues("%s0 Validation error. Invalid key in values. Specify a valid key."), + EmptyValueInValues("%s0 Validation error. Invalid value in values. Specify a valid value."), + TokensKeyError("%s0 Validation error. 'tokens' key is missing from the payload. Specify a 'tokens' key."), + EmptyTokens("%s0 Validation error. The 'tokens' field is empty. Specify tokens for one or more fields."), + EmptyKeyInTokens("%s0 Validation error. Invalid key tokens. Specify a valid key."), + EmptyValueInTokens("%s0 Validation error. Invalid value in tokens. Specify a valid value."), + EmptyUpsert("%s0 Validation error. 'upsert' key can't be empty. Specify an upsert column."), + EmptyUpsertValues("%s0 Validation error. Upsert column values can't be empty. Specify at least one upsert column."), + HomogenousNotSupportedWithUpsert("%s0 Validation error. 'homogenous' is not supported with 'upsert'. Specify either 'homogenous' or 'upsert'."), + TokensPassedForTokenModeDisable("%s0 Validation error. 'tokenMode' wasn't specified. Set 'tokenMode' to 'ENABLE' to insert tokens."), + NoTokensWithTokenMode("%s0 Validation error. Tokens weren't specified for records while 'tokenMode' was %s1. Specify tokens."), + MismatchOfFieldsAndTokens("%s0 Validation error. 'fields' and 'tokens' have different columns names. Verify that 'fields' and 'tokens' columns match."), + InsufficientTokensPassedForTokenModeEnableStrict("%s0 Validation error. 'tokenMode' is set to 'ENABLE_STRICT', but some fields are missing tokens. Specify tokens for all fields."), + BatchInsertPartialSuccess("%s0 Insert operation completed with partial success."), + BatchInsertFailure("%s0 Insert operation failed."), + RecordSizeExceedError("%s0 Maximum number of records exceeded. The limit is 10000."), + + // Detokenize + InvalidDetokenizeData("%s0 Validation error. Invalid detokenize data. Specify valid detokenize data."), + EmptyDetokenizeData("%s0 Validation error. Invalid data tokens. Specify at least one data token."), + EmptyTokenInDetokenizeData("%s0 Validation error. Invalid data tokens. Specify a valid data token."), + TokensSizeExceedError("%s0 Maximum number of tokens exceeded. The limit is 10000."), + + // Delete Tokens + DeleteTokensRequestNull("%s0 Validation error. DeleteTokensRequest object is null. Specify a valid DeleteTokensRequest object."), + EmptyDeleteTokensData("%s0 Validation error. Tokens list is empty. Specify at least one token to delete."), + EmptyTokenInDeleteTokensData("%s0 Validation error. Invalid token in delete tokens request. Specify a valid token."), + DeleteTokensSizeExceedError("%s0 Maximum number of tokens exceeded. The limit is 10000."), + + // Get + IdsKeyError("%s0 Validation error. 'ids' key is missing from the payload. Specify an 'ids' key."), + EmptyIds("%s0 Validation error. 'ids' can't be empty. Specify at least one id."), + EmptyIdInIds("%s0 Validation error. Invalid id in 'ids'. Specify a valid id."), + EmptyFields("%s0 Validation error. Fields are empty in get payload. Specify at least one field."), + EmptyFieldInFields("%s0 Validation error. Invalid field in 'fields'. Specify a valid field."), + RedactionKeyError("%s0 Validation error. 'redaction' key is missing from the payload. Specify a 'redaction' key."), + RedactionWithTokensNotSupported("%s0 Validation error. 'redaction' can't be used when 'returnTokens' is specified. Remove 'redaction' from payload if 'returnTokens' is specified."), + TokensGetColumnNotSupported("%s0 Validation error. Column name and/or column values can't be used when 'returnTokens' is specified. Remove unique column values or 'returnTokens' from the payload."), + EmptyOffset("%s0 Validation error. 'offset' can't be empty. Specify an offset."), + EmptyLimit("%s0 Validation error. 'limit' can't be empty. Specify a limit."), + UniqueColumnOrIdsKeyError("%s0 Validation error. 'ids' or 'columnName' key is missing from the payload. Specify the ids or unique 'columnName' in payload."), + BothIdsAndColumnDetailsSpecified("%s0 Validation error. Both Skyflow IDs and column details can't be specified. Either specify Skyflow IDs or unique column details."), + ColumnNameKeyError("%s0 Validation error. 'columnName' isn't specified whereas 'columnValues' are specified. Either add 'columnName' or remove 'columnValues'."), + EmptyColumnName("%s0 Validation error. 'columnName' can't be empty. Specify a column name."), + ColumnValuesKeyErrorGet("%s0 Validation error. 'columnValues' aren't specified whereas 'columnName' is specified. Either add 'columnValues' or remove 'columnName'."), + EmptyColumnValues("%s0 Validation error. 'columnValues' can't be empty. Specify at least one column value"), + EmptyValueInColumnValues("%s0 Validation error. Invalid value in column values. Specify a valid column value."), + + TokenKeyError("%s0 Validation error. 'token' key is missing from the payload. Specify a 'token' key."), + PartialSuccess("%s0 Validation error. Check 'SkyflowError.data' for details."), + + // Update + DataKeyError("%s0 Validation error. 'data' key is missing from the payload. Specify a 'data' key."), + EmptyData("%s0 Validation error. 'data' can't be empty. Specify data."), + SkyflowIdKeyError("%s0 Validation error. 'skyflow_id' is missing from the data payload. Specify a 'skyflow_id'."), + InvalidSkyflowIdType("%s0 Validation error. Invalid type for 'skyflow_id' in data payload. Specify 'skyflow_id' as a string."), + EmptySkyflowId("%s0 Validation error. 'skyflow_id' can't be empty. Specify a skyflow id."), + + // Query + QueryKeyError("%s0 Validation error. 'query' key is missing from the payload. Specify a 'query' key."), + EmptyQuery("%s0 Validation error. 'query' can't be empty. Specify a query"), + + // Tokenize + ColumnValuesKeyErrorTokenize("%s0 Validation error. 'columnValues' key is missing from the payload. Specify a 'columnValues' key."), + EmptyColumnGroupInColumnValue("%s0 Validation error. Invalid column group in column value. Specify a valid column group."), + TokenizeRequestNull("%s0 Validation error. TokenizeRequest object is null. Specify a valid TokenizeRequest object."), + EmptyTokenizeData("%s0 Validation error. Tokenize data is empty. Specify at least one tokenize record."), + TokenizeRecordNull("%s0 Validation error. TokenizeRecord in the list is null. Specify a valid TokenizeRecord object."), + EmptyValueInTokenizeRecord("%s0 Validation error. Value in TokenizeRecord is null or empty. Specify a valid value."), + EmptyTokenGroupNamesInTokenizeRecord("%s0 Validation error. TokenGroupNames in TokenizeRecord is null or empty. Specify at least one token group name."), + EmptyTokenGroupNameInTokenizeRecord("%s0 Validation error. Token group name in TokenizeRecord is null or empty. Specify a valid token group name."), + TokenizeDataSizeExceedError("%s0 Maximum number of tokenize records exceeded. The limit is 10000."), + + // Connection + InvalidRequestHeaders("%s0 Validation error. Request headers aren't valid. Specify valid request headers."), + EmptyRequestHeaders("%s0 Validation error. Request headers are empty. Specify valid request headers."), + InvalidPathParams("%s0 Validation error. Path parameters aren't valid. Specify valid path parameters."), + EmptyPathParams("%s0 Validation error. Path parameters are empty. Specify valid path parameters."), + InvalidQueryParams("%s0 Validation error. Query parameters aren't valid. Specify valid query parameters."), + EmptyQueryParams("%s0 Validation error. Query parameters are empty. Specify valid query parameters."), + InvalidRequestBody("%s0 Validation error. Invalid request body. Specify the request body as an object."), + EmptyRequestBody("%s0 Validation error. Request body can't be empty. Specify a valid request body."), + + // File upload + ColumnNameKeyErrorFileUpload("%s0 Validation error. columnName is missing from the payload. Specify a columnName key."), + MissingFileSourceInUploadFileRequest("%s0 Validation error. Provide exactly one of filePath, base64, or fileObject."), + FileNameMustBeProvidedWithFileObject("%s0 Validation error. fileName must be provided when using fileObject."), + InvalidFileObject("%s0 Validation error. Invalid file object in file upload request. Specify a valid file object."), + InvalidBase64("%s0 Validation error. Invalid base64 string in file upload request. Specify a valid base64 string."), + + // detect + InvalidTextInDeIdentify("%s0 Validation error. The text field is required and must be a non-empty string. Specify a valid text."), + InvalidTextInReIdentify("%s0 Validation error. The text field is required and must be a non-empty string. Specify a valid text."), + + //Detect Files + InvalidNullFileInDeIdentifyFile("%s0 Validation error. The file field is required and must not be null. Specify a valid file object."), + InvalidFilePath("%s0 Validation error. The file path is invalid. Specify a valid file path."), + BothFileAndFilePathProvided("%s0 Validation error. Both file and filePath are provided. Specify either file object or filePath, not both."), + FileNotFoundToDeidentify("%s0 Validation error. The file to deidentify was not found at the specified path. Verify the file path and try again."), + FileNotReadableToDeidentify("%s0 Validation error. The file to deidentify is not readable. Check the file permissions and try again."), + InvalidPixelDensityToDeidentifyFile("%s0 Validation error. Should be a positive integer. Specify a valid pixel density."), + InvalidMaxResolution("%s0 Validation error. Should be a positive integer. Specify a valid max resolution."), + OutputDirectoryNotFound("%s0 Validation error. The output directory for deidentified files was not found at the specified path. Verify the output directory path and try again."), + InvalidPermission("%s0 Validation error. The output directory for deidentified files is not writable. Check the directory permissions and try again."), + InvalidWaitTime("%s0 Validation error. The wait time for deidentify file operation should be a positive integer. Specify a valid wait time."), + WaitTimeExceedsLimit("%s0 Validation error. The wait time for deidentify file operation exceeds the maximum limit of 64 seconds. Specify a wait time less than or equal to 60 seconds."), + InvalidOrEmptyRunId("%s0 Validation error. The run ID is invalid or empty. Specify a valid run ID."), + FailedToEncodeFile("%s0 Validation error. Failed to encode the file. Ensure the file is in a supported format and try again."), + FailedToDecodeFileFromResponse("%s0 Failed to decode the file from the response. Ensure the response is valid and try again."), + EmptyFileAndFilePathInDeIdentifyFile("%s0 Validation error. Both file and filePath are empty. Specify either file object or filePath, not both."), + VaultTokenFormatIsNotAllowedForFiles("%s0 Validation error. Vault token format is not allowed for deidentify file request."), + PollingForResultsFailed("%s0 API error. Polling for results failed. Unable to retrieve the deidentified file"), + FailedToSaveProcessedFile("%s0 Validation error. Failed to save the processed file. Ensure the output directory is valid and writable."), + InvalidAudioFileType("%s0 Validation error. The file type is not supported. Specify a valid file type mp3 or wav."), + // Generic + ErrorOccurred("%s0 API error. Error occurred."), + + DetokenizeRequestNull("%s0 Validation error. DetokenizeRequest object is null. Specify a valid DetokenizeRequest object."), + + NullTokenGroupRedactions("%s0 Validation error. TokenGroupRedaction in the list is null. Specify a valid TokenGroupRedactions object."), + + NullRedactionInTokenGroup("%s0 Validation error. Redaction in TokenGroupRedactions is null or empty. Specify a valid redaction."), + + NullTokenGroupNameInTokenGroup("%s0 Validation error. TokenGroupName in TokenGroupRedactions is null or empty. Specify a valid tokenGroupName."), + InvalidRecord("%s0 Validation error. InsertRecord object in the list is invalid. Specify a valid InsertRecord object."), + ; + + private final String message; + + ErrorMessage(String message) { + this.message = message.replace("%s0", SdkVersion.getSdkPrefix()); + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/com/skyflow/errors/HttpStatus.java b/common/src/main/java/com/skyflow/errors/HttpStatus.java similarity index 100% rename from src/main/java/com/skyflow/errors/HttpStatus.java rename to common/src/main/java/com/skyflow/errors/HttpStatus.java diff --git a/common/src/main/java/com/skyflow/errors/SkyflowException.java b/common/src/main/java/com/skyflow/errors/SkyflowException.java new file mode 100644 index 00000000..138fcc68 --- /dev/null +++ b/common/src/main/java/com/skyflow/errors/SkyflowException.java @@ -0,0 +1,135 @@ +package com.skyflow.errors; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.skyflow.utils.BaseConstants; + +import java.util.List; +import java.util.Map; + +public class SkyflowException extends Exception { + private String requestId; + private Integer grpcCode; + private Integer httpCode; + private String message; + private String httpStatus; + private JsonArray details; + private JsonObject responseBody; + + public SkyflowException(String message) { + super(message); + this.message = message; + } + + public SkyflowException(Throwable cause) { + super(cause); + this.message = cause.getMessage(); + } + + public SkyflowException(String message, Throwable cause) { + super(message, cause); + this.message = message; + } + + public SkyflowException(int code, String message) { + super(message); + this.httpCode = code; + this.message = message; + this.httpStatus = HttpStatus.BAD_REQUEST.getHttpStatus(); + this.details = new JsonArray(); + } + + public SkyflowException(int httpCode, Throwable cause, Map> responseHeaders, String responseBody) { + super(cause); + this.httpCode = httpCode > 0 ? httpCode : 400; + try { + setRequestId(responseHeaders); + setResponseBody(responseBody, responseHeaders); + } catch (Exception e) { + this.httpStatus = HttpStatus.BAD_REQUEST.getHttpStatus(); + String fullMessage = responseBody != null ? responseBody : + (cause.getLocalizedMessage() != null ? cause.getMessage() : ErrorMessage.ErrorOccurred.getMessage()); + this.message = fullMessage.split("HTTP response code:")[0].trim(); + } + } + + private void setResponseBody(String responseBody, Map> responseHeaders) { + this.responseBody = JsonParser.parseString(responseBody).getAsJsonObject(); + if (this.responseBody.get("error") != null) { + setGrpcCode(); + setHttpStatus(); + setMessage(); + setDetails(responseHeaders); + } + } + + public String getRequestId() { + return requestId; + } + + private void setRequestId(Map> responseHeaders) { + List ids = responseHeaders.get(BaseConstants.REQUEST_ID_HEADER_KEY); + this.requestId = ids == null ? null : ids.get(0); + } + + private void setMessage() { + JsonElement messageElement = ((JsonObject) responseBody.get("error")).get("message"); + this.message = messageElement == null ? null : messageElement.getAsString(); + } + + private void setGrpcCode() { + JsonElement grpcElement = ((JsonObject) responseBody.get("error")).get("grpc_code"); + this.grpcCode = grpcElement == null ? null : grpcElement.getAsInt(); + } + + private void setHttpStatus() { + JsonElement statusElement = ((JsonObject) responseBody.get("error")).get("http_status"); + this.httpStatus = statusElement == null ? null : statusElement.getAsString(); + } + + public int getHttpCode() { + return httpCode; + } + + public JsonArray getDetails() { + return details; + } + + private void setDetails(Map> responseHeaders) { + JsonElement detailsElement = ((JsonObject) responseBody.get("error")).get("details"); + List errorFromClientHeader = responseHeaders.get(BaseConstants.ERROR_FROM_CLIENT_HEADER_KEY); + if (detailsElement != null) { + this.details = detailsElement.getAsJsonArray(); + } + if (errorFromClientHeader != null) { + this.details = this.details == null ? new JsonArray() : this.details; + String errorFromClient = errorFromClientHeader.get(0); + JsonObject detailObject = new JsonObject(); + detailObject.addProperty("errorFromClient", errorFromClient); + this.details.add(detailObject); + } + } + + public Integer getGrpcCode() { + return grpcCode; + } + + public String getHttpStatus() { + return httpStatus; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public String toString() { + return String.format( + "%n requestId: %s%n grpcCode: %s%n httpCode: %s%n httpStatus: %s%n message: %s%n details: %s", + this.requestId, this.grpcCode, this.httpCode, this.httpStatus, this.message, this.details + ); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java new file mode 100644 index 00000000..a1dd3aae --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java @@ -0,0 +1,29 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest; + +import com.skyflow.generated.auth.rest.core.ClientOptions; +import com.skyflow.generated.auth.rest.core.Suppliers; +import com.skyflow.generated.auth.rest.resources.authentication.AuthenticationClient; + +import java.util.function.Supplier; + +public class ApiClient { + protected final ClientOptions clientOptions; + + protected final Supplier authenticationClient; + + public ApiClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.authenticationClient = Suppliers.memoize(() -> new AuthenticationClient(clientOptions)); + } + + public AuthenticationClient authentication() { + return this.authenticationClient.get(); + } + + public static ApiClientBuilder builder() { + return new ApiClientBuilder(); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java new file mode 100644 index 00000000..aed3ed24 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java @@ -0,0 +1,67 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest; + +import com.skyflow.generated.auth.rest.core.ClientOptions; +import com.skyflow.generated.auth.rest.core.Environment; +import okhttp3.OkHttpClient; + +public final class ApiClientBuilder { + private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); + + private String token = null; + + private Environment environment = Environment.PRODUCTION; + + /** + * Sets token + */ + public ApiClientBuilder token(String token) { + this.token = token; + return this; + } + + public ApiClientBuilder environment(Environment environment) { + this.environment = environment; + return this; + } + + public ApiClientBuilder url(String url) { + this.environment = Environment.custom(url); + return this; + } + + /** + * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. + */ + public ApiClientBuilder timeout(int timeout) { + this.clientOptionsBuilder.timeout(timeout); + return this; + } + + /** + * Sets the maximum number of retries for the client. Defaults to 2 retries. + */ + public ApiClientBuilder maxRetries(int maxRetries) { + this.clientOptionsBuilder.maxRetries(maxRetries); + return this; + } + + /** + * Sets the underlying OkHttp client + */ + public ApiClientBuilder httpClient(OkHttpClient httpClient) { + this.clientOptionsBuilder.httpClient(httpClient); + return this; + } + + public ApiClient build() { + if (token == null) { + throw new RuntimeException("Please provide token"); + } + this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + this.token); + clientOptionsBuilder.environment(this.environment); + return new ApiClient(clientOptionsBuilder.build()); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java new file mode 100644 index 00000000..748eb02e --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java @@ -0,0 +1,29 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest; + +import com.skyflow.generated.auth.rest.core.ClientOptions; +import com.skyflow.generated.auth.rest.core.Suppliers; +import com.skyflow.generated.auth.rest.resources.authentication.AsyncAuthenticationClient; + +import java.util.function.Supplier; + +public class AsyncApiClient { + protected final ClientOptions clientOptions; + + protected final Supplier authenticationClient; + + public AsyncApiClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.authenticationClient = Suppliers.memoize(() -> new AsyncAuthenticationClient(clientOptions)); + } + + public AsyncAuthenticationClient authentication() { + return this.authenticationClient.get(); + } + + public static AsyncApiClientBuilder builder() { + return new AsyncApiClientBuilder(); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java new file mode 100644 index 00000000..2e30d45a --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java @@ -0,0 +1,67 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest; + +import com.skyflow.generated.auth.rest.core.ClientOptions; +import com.skyflow.generated.auth.rest.core.Environment; +import okhttp3.OkHttpClient; + +public final class AsyncApiClientBuilder { + private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); + + private String token = null; + + private Environment environment = Environment.PRODUCTION; + + /** + * Sets token + */ + public AsyncApiClientBuilder token(String token) { + this.token = token; + return this; + } + + public AsyncApiClientBuilder environment(Environment environment) { + this.environment = environment; + return this; + } + + public AsyncApiClientBuilder url(String url) { + this.environment = Environment.custom(url); + return this; + } + + /** + * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. + */ + public AsyncApiClientBuilder timeout(int timeout) { + this.clientOptionsBuilder.timeout(timeout); + return this; + } + + /** + * Sets the maximum number of retries for the client. Defaults to 2 retries. + */ + public AsyncApiClientBuilder maxRetries(int maxRetries) { + this.clientOptionsBuilder.maxRetries(maxRetries); + return this; + } + + /** + * Sets the underlying OkHttp client + */ + public AsyncApiClientBuilder httpClient(OkHttpClient httpClient) { + this.clientOptionsBuilder.httpClient(httpClient); + return this; + } + + public AsyncApiClient build() { + if (token == null) { + throw new RuntimeException("Please provide token"); + } + this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + this.token); + clientOptionsBuilder.environment(this.environment); + return new AsyncApiClient(clientOptionsBuilder.build()); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientApiException.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientApiException.java new file mode 100644 index 00000000..53d67f0b --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientApiException.java @@ -0,0 +1,74 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.Response; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This exception type will be thrown for any non-2XX API responses. + */ +public class ApiClientApiException extends ApiClientException { + /** + * The error code of the response that triggered the exception. + */ + private final int statusCode; + + /** + * The body of the response that triggered the exception. + */ + private final Object body; + + private final Map> headers; + + public ApiClientApiException(String message, int statusCode, Object body) { + super(message); + this.statusCode = statusCode; + this.body = body; + this.headers = new HashMap<>(); + } + + public ApiClientApiException(String message, int statusCode, Object body, Response rawResponse) { + super(message); + this.statusCode = statusCode; + this.body = body; + this.headers = new HashMap<>(); + rawResponse.headers().forEach(header -> { + String key = header.component1(); + String value = header.component2(); + this.headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value); + }); + } + + /** + * @return the statusCode + */ + public int statusCode() { + return this.statusCode; + } + + /** + * @return the body + */ + public Object body() { + return this.body; + } + + /** + * @return the headers + */ + public Map> headers() { + return this.headers; + } + + @Override + public String toString() { + return "ApiClientApiException{" + "message: " + getMessage() + ", statusCode: " + statusCode + ", body: " + body + + "}"; + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientException.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientException.java new file mode 100644 index 00000000..f08afa2e --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientException.java @@ -0,0 +1,17 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +/** + * This class serves as the base exception for all errors in the SDK. + */ +public class ApiClientException extends RuntimeException { + public ApiClientException(String message) { + super(message); + } + + public ApiClientException(String message, Exception e) { + super(message, e); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientHttpResponse.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientHttpResponse.java new file mode 100644 index 00000000..8a28d22f --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientHttpResponse.java @@ -0,0 +1,38 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.Response; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class ApiClientHttpResponse { + + private final T body; + + private final Map> headers; + + public ApiClientHttpResponse(T body, Response rawResponse) { + this.body = body; + + Map> headers = new HashMap<>(); + rawResponse.headers().forEach(header -> { + String key = header.component1(); + String value = header.component2(); + headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value); + }); + this.headers = headers; + } + + public T body() { + return this.body; + } + + public Map> headers() { + return headers; + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java new file mode 100644 index 00000000..4eee6b92 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java @@ -0,0 +1,171 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.OkHttpClient; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public final class ClientOptions { + private final Environment environment; + + private final Map headers; + + private final Map> headerSuppliers; + + private final OkHttpClient httpClient; + + private final int timeout; + + private ClientOptions( + Environment environment, + Map headers, + Map> headerSuppliers, + OkHttpClient httpClient, + int timeout) { + this.environment = environment; + this.headers = new HashMap<>(); + this.headers.putAll(headers); + this.headers.putAll(new HashMap() { + { + put("X-Fern-Language", "JAVA"); + put("X-Fern-SDK-Name", "com.skyflow.generated.rest.fern:api-sdk"); + put("X-Fern-SDK-Version", "0.0.279"); + } + }); + this.headerSuppliers = headerSuppliers; + this.httpClient = httpClient; + this.timeout = timeout; + } + + public Environment environment() { + return this.environment; + } + + public Map headers(RequestOptions requestOptions) { + Map values = new HashMap<>(this.headers); + headerSuppliers.forEach((key, supplier) -> { + values.put(key, supplier.get()); + }); + if (requestOptions != null) { + values.putAll(requestOptions.getHeaders()); + } + return values; + } + + public int timeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.timeout; + } + return requestOptions.getTimeout().orElse(this.timeout); + } + + public OkHttpClient httpClient() { + return this.httpClient; + } + + public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.httpClient; + } + return this.httpClient + .newBuilder() + .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit()) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private Environment environment; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + private int maxRetries = 2; + + private Optional timeout = Optional.empty(); + + private OkHttpClient httpClient = null; + + public Builder environment(Environment environment) { + this.environment = environment; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(int timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(Optional timeout) { + this.timeout = timeout; + return this; + } + + /** + * Override the maximum number of retries. Defaults to 2 retries. + */ + public Builder maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + public Builder httpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + public ClientOptions build() { + OkHttpClient.Builder httpClientBuilder = + this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder(); + + if (this.httpClient != null) { + timeout.ifPresent(timeout -> httpClientBuilder + .callTimeout(timeout, TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS)); + } else { + httpClientBuilder + .callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .addInterceptor(new RetryInterceptor(this.maxRetries)); + } + + this.httpClient = httpClientBuilder.build(); + this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000); + + return new ClientOptions(environment, headers, headerSuppliers, httpClient, this.timeout.get()); + } + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/DateTimeDeserializer.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/DateTimeDeserializer.java new file mode 100644 index 00000000..dfa25a82 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/DateTimeDeserializer.java @@ -0,0 +1,56 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; + +/** + * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects. + */ +class DateTimeDeserializer extends JsonDeserializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule().addDeserializer(OffsetDateTime.class, new DateTimeDeserializer()); + } + + /** + * Gets a module wrapping this deserializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + JsonToken token = parser.currentToken(); + if (token == JsonToken.VALUE_NUMBER_INT) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC); + } else { + TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( + parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from); + + if (temporal.query(TemporalQueries.offset()) == null) { + return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC); + } else { + return OffsetDateTime.from(temporal); + } + } + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Environment.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Environment.java new file mode 100644 index 00000000..098667c0 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Environment.java @@ -0,0 +1,24 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +public final class Environment { + public static final Environment PRODUCTION = new Environment("https://manage.skyflowapis.com"); + + public static final Environment SANDBOX = new Environment("https://manage.skyflowapis-preview.com"); + + private final String url; + + private Environment(String url) { + this.url = url; + } + + public String getUrl() { + return this.url; + } + + public static Environment custom(String url) { + return new Environment(url); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/FileStream.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/FileStream.java new file mode 100644 index 00000000..0e878ed3 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/FileStream.java @@ -0,0 +1,61 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.MediaType; +import okhttp3.RequestBody; +import org.jetbrains.annotations.Nullable; + +import java.io.InputStream; +import java.util.Objects; + +/** + * Represents a file stream with associated metadata for file uploads. + */ +public class FileStream { + private final InputStream inputStream; + private final String fileName; + private final MediaType contentType; + + /** + * Constructs a FileStream with the given input stream and optional metadata. + * + * @param inputStream The input stream of the file content. Must not be null. + * @param fileName The name of the file, or null if unknown. + * @param contentType The MIME type of the file content, or null if unknown. + * @throws NullPointerException if inputStream is null + */ + public FileStream(InputStream inputStream, @Nullable String fileName, @Nullable MediaType contentType) { + this.inputStream = Objects.requireNonNull(inputStream, "Input stream cannot be null"); + this.fileName = fileName; + this.contentType = contentType; + } + + public FileStream(InputStream inputStream) { + this(inputStream, null, null); + } + + public InputStream getInputStream() { + return inputStream; + } + + @Nullable + public String getFileName() { + return fileName; + } + + @Nullable + public MediaType getContentType() { + return contentType; + } + + /** + * Creates a RequestBody suitable for use with OkHttp client. + * + * @return A RequestBody instance representing this file stream. + */ + public RequestBody toRequestBody() { + return new InputStreamRequestBody(contentType, inputStream); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/InputStreamRequestBody.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/InputStreamRequestBody.java new file mode 100644 index 00000000..a94faec9 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/InputStreamRequestBody.java @@ -0,0 +1,80 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okhttp3.internal.Util; +import okio.BufferedSink; +import okio.Okio; +import okio.Source; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; + +/** + * A custom implementation of OkHttp's RequestBody that wraps an InputStream. + * This class allows streaming of data from an InputStream directly to an HTTP request body, + * which is useful for file uploads or sending large amounts of data without loading it all into memory. + */ +public class InputStreamRequestBody extends RequestBody { + private final InputStream inputStream; + private final MediaType contentType; + + /** + * Constructs an InputStreamRequestBody with the specified content type and input stream. + * + * @param contentType the MediaType of the content, or null if not known + * @param inputStream the InputStream containing the data to be sent + * @throws NullPointerException if inputStream is null + */ + public InputStreamRequestBody(@Nullable MediaType contentType, InputStream inputStream) { + this.contentType = contentType; + this.inputStream = Objects.requireNonNull(inputStream, "inputStream == null"); + } + + /** + * Returns the content type of this request body. + * + * @return the MediaType of the content, or null if not specified + */ + @Nullable + @Override + public MediaType contentType() { + return contentType; + } + + /** + * Returns the content length of this request body, if known. + * This method attempts to determine the length using the InputStream's available() method, + * which may not always accurately reflect the total length of the stream. + * + * @return the content length, or -1 if the length is unknown + * @throws IOException if an I/O error occurs + */ + @Override + public long contentLength() throws IOException { + return inputStream.available() == 0 ? -1 : inputStream.available(); + } + + /** + * Writes the content of the InputStream to the given BufferedSink. + * This method is responsible for transferring the data from the InputStream to the network request. + * + * @param sink the BufferedSink to write the content to + * @throws IOException if an I/O error occurs during writing + */ + @Override + public void writeTo(BufferedSink sink) throws IOException { + Source source = null; + try { + source = Okio.source(inputStream); + sink.writeAll(source); + } finally { + Util.closeQuietly(Objects.requireNonNull(source)); + } + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/MediaTypes.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/MediaTypes.java new file mode 100644 index 00000000..d4374647 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/MediaTypes.java @@ -0,0 +1,13 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.MediaType; + +public final class MediaTypes { + + public static final MediaType APPLICATION_JSON = MediaType.parse("application/json"); + + private MediaTypes() {} +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Nullable.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Nullable.java new file mode 100644 index 00000000..efabe806 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Nullable.java @@ -0,0 +1,140 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import java.util.Optional; +import java.util.function.Function; + +public final class Nullable { + + private final Either, Null> value; + + private Nullable() { + this.value = Either.left(Optional.empty()); + } + + private Nullable(T value) { + if (value == null) { + this.value = Either.right(Null.INSTANCE); + } else { + this.value = Either.left(Optional.of(value)); + } + } + + public static Nullable ofNull() { + return new Nullable<>(null); + } + + public static Nullable of(T value) { + return new Nullable<>(value); + } + + public static Nullable empty() { + return new Nullable<>(); + } + + public static Nullable ofOptional(Optional value) { + if (value.isPresent()) { + return of(value.get()); + } else { + return empty(); + } + } + + public boolean isNull() { + return this.value.isRight(); + } + + public boolean isEmpty() { + return this.value.isLeft() && !this.value.getLeft().isPresent(); + } + + public T get() { + if (this.isNull()) { + return null; + } + + return this.value.getLeft().get(); + } + + public Nullable map(Function mapper) { + if (this.isNull()) { + return Nullable.ofNull(); + } + + return Nullable.ofOptional(this.value.getLeft().map(mapper)); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Nullable)) { + return false; + } + + if (((Nullable) other).isNull() && this.isNull()) { + return true; + } + + return this.value.getLeft().equals(((Nullable) other).value.getLeft()); + } + + private static final class Either { + private L left = null; + private R right = null; + + private Either(L left, R right) { + if (left != null && right != null) { + throw new IllegalArgumentException("Left and right argument cannot both be non-null."); + } + + if (left == null && right == null) { + throw new IllegalArgumentException("Left and right argument cannot both be null."); + } + + if (left != null) { + this.left = left; + } + + if (right != null) { + this.right = right; + } + } + + public static Either left(L left) { + return new Either<>(left, null); + } + + public static Either right(R right) { + return new Either<>(null, right); + } + + public boolean isLeft() { + return this.left != null; + } + + public boolean isRight() { + return this.right != null; + } + + public L getLeft() { + if (!this.isLeft()) { + throw new IllegalArgumentException("Cannot get left from right Either."); + } + return this.left; + } + + public R getRight() { + if (!this.isRight()) { + throw new IllegalArgumentException("Cannot get right from left Either."); + } + return this.right; + } + } + + private static final class Null { + private static final Null INSTANCE = new Null(); + + private Null() {} + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/NullableNonemptyFilter.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/NullableNonemptyFilter.java new file mode 100644 index 00000000..dd32d66c --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/NullableNonemptyFilter.java @@ -0,0 +1,19 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import java.util.Optional; + +public final class NullableNonemptyFilter { + @Override + public boolean equals(Object o) { + boolean isOptionalEmpty = isOptionalEmpty(o); + + return isOptionalEmpty; + } + + private boolean isOptionalEmpty(Object o) { + return o instanceof Optional && !((Optional) o).isPresent(); + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ObjectMappers.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ObjectMappers.java new file mode 100644 index 00000000..4997b3ca --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ObjectMappers.java @@ -0,0 +1,37 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import java.io.IOException; + +public final class ObjectMappers { + public static final ObjectMapper JSON_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .addModule(new JavaTimeModule()) + .addModule(DateTimeDeserializer.getModule()) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + + private ObjectMappers() {} + + public static String stringify(Object o) { + try { + return JSON_MAPPER + .setSerializationInclusion(JsonInclude.Include.ALWAYS) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(o); + } catch (IOException e) { + return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); + } + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/QueryStringMapper.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/QueryStringMapper.java new file mode 100644 index 00000000..8b1f9f7e --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/QueryStringMapper.java @@ -0,0 +1,139 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import okhttp3.HttpUrl; +import okhttp3.MultipartBody; + +import java.util.*; + +public class QueryStringMapper { + + private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER; + + public static void addQueryParameter(HttpUrl.Builder httpUrl, String key, Object value, boolean arraysAsRepeats) { + JsonNode valueNode = MAPPER.valueToTree(value); + + List> flat; + if (valueNode.isObject()) { + flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats); + } else if (valueNode.isArray()) { + flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats); + } else { + if (valueNode.isTextual()) { + httpUrl.addQueryParameter(key, valueNode.textValue()); + } else { + httpUrl.addQueryParameter(key, valueNode.toString()); + } + return; + } + + for (Map.Entry field : flat) { + if (field.getValue().isTextual()) { + httpUrl.addQueryParameter(key + field.getKey(), field.getValue().textValue()); + } else { + httpUrl.addQueryParameter(key + field.getKey(), field.getValue().toString()); + } + } + } + + public static void addFormDataPart( + MultipartBody.Builder multipartBody, String key, Object value, boolean arraysAsRepeats) { + JsonNode valueNode = MAPPER.valueToTree(value); + + List> flat; + if (valueNode.isObject()) { + flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats); + } else if (valueNode.isArray()) { + flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats); + } else { + if (valueNode.isTextual()) { + multipartBody.addFormDataPart(key, valueNode.textValue()); + } else { + multipartBody.addFormDataPart(key, valueNode.toString()); + } + return; + } + + for (Map.Entry field : flat) { + if (field.getValue().isTextual()) { + multipartBody.addFormDataPart( + key + field.getKey(), field.getValue().textValue()); + } else { + multipartBody.addFormDataPart( + key + field.getKey(), field.getValue().toString()); + } + } + } + + public static List> flattenObject(ObjectNode object, boolean arraysAsRepeats) { + List> flat = new ArrayList<>(); + + Iterator> fields = object.fields(); + while (fields.hasNext()) { + Map.Entry field = fields.next(); + + String key = "[" + field.getKey() + "]"; + + if (field.getValue().isObject()) { + List> flatField = + flattenObject((ObjectNode) field.getValue(), arraysAsRepeats); + addAll(flat, flatField, key); + } else if (field.getValue().isArray()) { + List> flatField = + flattenArray((ArrayNode) field.getValue(), key, arraysAsRepeats); + addAll(flat, flatField, ""); + } else { + flat.add(new AbstractMap.SimpleEntry<>(key, field.getValue())); + } + } + + return flat; + } + + private static List> flattenArray( + ArrayNode array, String key, boolean arraysAsRepeats) { + List> flat = new ArrayList<>(); + + Iterator elements = array.elements(); + + int index = 0; + while (elements.hasNext()) { + JsonNode element = elements.next(); + + String indexKey = key + "[" + index + "]"; + + if (arraysAsRepeats) { + indexKey = key; + } + + if (element.isObject()) { + List> flatField = flattenObject((ObjectNode) element, arraysAsRepeats); + addAll(flat, flatField, indexKey); + } else if (element.isArray()) { + List> flatField = flattenArray((ArrayNode) element, "", arraysAsRepeats); + addAll(flat, flatField, indexKey); + } else { + flat.add(new AbstractMap.SimpleEntry<>(indexKey, element)); + } + + index++; + } + + return flat; + } + + private static void addAll( + List> target, List> source, String prefix) { + for (Map.Entry entry : source) { + Map.Entry entryToAdd = + new AbstractMap.SimpleEntry<>(prefix + entry.getKey(), entry.getValue()); + target.add(entryToAdd); + } + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/RequestOptions.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/RequestOptions.java new file mode 100644 index 00000000..b70c02df --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/RequestOptions.java @@ -0,0 +1,101 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public final class RequestOptions { + private final String token; + + private final Optional timeout; + + private final TimeUnit timeoutTimeUnit; + + private final Map headers; + + private final Map> headerSuppliers; + + private RequestOptions( + String token, + Optional timeout, + TimeUnit timeoutTimeUnit, + Map headers, + Map> headerSuppliers) { + this.token = token; + this.timeout = timeout; + this.timeoutTimeUnit = timeoutTimeUnit; + this.headers = headers; + this.headerSuppliers = headerSuppliers; + } + + public Optional getTimeout() { + return timeout; + } + + public TimeUnit getTimeoutTimeUnit() { + return timeoutTimeUnit; + } + + public Map getHeaders() { + Map headers = new HashMap<>(); + if (this.token != null) { + headers.put("Authorization", "Bearer " + this.token); + } + headers.putAll(this.headers); + this.headerSuppliers.forEach((key, supplier) -> { + headers.put(key, supplier.get()); + }); + return headers; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private String token = null; + + private Optional timeout = Optional.empty(); + + private TimeUnit timeoutTimeUnit = TimeUnit.SECONDS; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + public Builder token(String token) { + this.token = token; + return this; + } + + public Builder timeout(Integer timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + public Builder timeout(Integer timeout, TimeUnit timeoutTimeUnit) { + this.timeout = Optional.of(timeout); + this.timeoutTimeUnit = timeoutTimeUnit; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + public RequestOptions build() { + return new RequestOptions(token, timeout, timeoutTimeUnit, headers, headerSuppliers); + } + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyInputStream.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyInputStream.java new file mode 100644 index 00000000..1d0a9110 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyInputStream.java @@ -0,0 +1,46 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.Response; + +import java.io.FilterInputStream; +import java.io.IOException; + +/** + * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the + * OkHttp Response object is properly closed when the stream is closed. + * + * This class extends FilterInputStream and takes an OkHttp Response object as a parameter. + * It retrieves the InputStream from the Response and overrides the close method to close + * both the InputStream and the Response object, ensuring proper resource management and preventing + * premature closure of the underlying HTTP connection. + */ +public class ResponseBodyInputStream extends FilterInputStream { + private final Response response; + + /** + * Constructs a ResponseBodyInputStream that wraps the InputStream from the given OkHttp + * Response object. + * + * @param response the OkHttp Response object from which the InputStream is retrieved + * @throws IOException if an I/O error occurs while retrieving the InputStream + */ + public ResponseBodyInputStream(Response response) throws IOException { + super(response.body().byteStream()); + this.response = response; + } + + /** + * Closes the InputStream and the associated OkHttp Response object. This ensures that the + * underlying HTTP connection is properly closed after the stream is no longer needed. + * + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + super.close(); + response.close(); // Ensure the response is closed when the stream is closed + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyReader.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyReader.java new file mode 100644 index 00000000..f4dfb17b --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyReader.java @@ -0,0 +1,45 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.Response; + +import java.io.FilterReader; +import java.io.IOException; + +/** + * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the + * OkHttp Response object is properly closed when the reader is closed. + * + * This class extends FilterReader and takes an OkHttp Response object as a parameter. + * It retrieves the Reader from the Response and overrides the close method to close + * both the Reader and the Response object, ensuring proper resource management and preventing + * premature closure of the underlying HTTP connection. + */ +public class ResponseBodyReader extends FilterReader { + private final Response response; + + /** + * Constructs a ResponseBodyReader that wraps the Reader from the given OkHttp Response object. + * + * @param response the OkHttp Response object from which the Reader is retrieved + * @throws IOException if an I/O error occurs while retrieving the Reader + */ + public ResponseBodyReader(Response response) throws IOException { + super(response.body().charStream()); + this.response = response; + } + + /** + * Closes the Reader and the associated OkHttp Response object. This ensures that the + * underlying HTTP connection is properly closed after the reader is no longer needed. + * + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + super.close(); + response.close(); // Ensure the response is closed when the reader is closed + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java new file mode 100644 index 00000000..8344b974 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java @@ -0,0 +1,79 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import okhttp3.Interceptor; +import okhttp3.Response; + +import java.io.IOException; +import java.time.Duration; +import java.util.Optional; +import java.util.Random; + +public class RetryInterceptor implements Interceptor { + + private static final Duration ONE_SECOND = Duration.ofSeconds(1); + private final ExponentialBackoff backoff; + private final Random random = new Random(); + + public RetryInterceptor(int maxRetries) { + this.backoff = new ExponentialBackoff(maxRetries); + } + + @Override + public Response intercept(Chain chain) throws IOException { + Response response = chain.proceed(chain.request()); + + if (shouldRetry(response.code())) { + return retryChain(response, chain); + } + + return response; + } + + private Response retryChain(Response response, Chain chain) throws IOException { + Optional nextBackoff = this.backoff.nextBackoff(); + while (nextBackoff.isPresent()) { + try { + Thread.sleep(nextBackoff.get().toMillis()); + } catch (InterruptedException e) { + throw new IOException("Interrupted while trying request", e); + } + response.close(); + response = chain.proceed(chain.request()); + if (shouldRetry(response.code())) { + nextBackoff = this.backoff.nextBackoff(); + } else { + return response; + } + } + + return response; + } + + private static boolean shouldRetry(int statusCode) { + return statusCode == 408 || statusCode == 429 || statusCode >= 500; + } + + private final class ExponentialBackoff { + + private final int maxNumRetries; + + private int retryNumber = 0; + + ExponentialBackoff(int maxNumRetries) { + this.maxNumRetries = maxNumRetries; + } + + public Optional nextBackoff() { + retryNumber += 1; + if (retryNumber > maxNumRetries) { + return Optional.empty(); + } + + int upperBound = (int) Math.pow(2, retryNumber); + return Optional.of(ONE_SECOND.multipliedBy(random.nextInt(upperBound))); + } + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java new file mode 100644 index 00000000..4a984faa --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java @@ -0,0 +1,97 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import java.io.Reader; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Scanner; + +/** + * The {@code Stream} class implements {@link Iterable} to provide a simple mechanism for reading and parsing + * objects of a given type from data streamed via a {@link Reader} using a specified delimiter. + *

+ * {@code Stream} assumes that data is being pushed to the provided {@link Reader} asynchronously and utilizes a + * {@code Scanner} to block during iteration if the next object is not available. + * + * @param The type of objects in the stream. + */ +public final class Stream implements Iterable { + /** + * The {@link Class} of the objects in the stream. + */ + private final Class valueType; + /** + * The {@link Scanner} used for reading from the input stream and blocking when needed during iteration. + */ + private final Scanner scanner; + + /** + * Constructs a new {@code Stream} with the specified value type, reader, and delimiter. + * + * @param valueType The class of the objects in the stream. + * @param reader The reader that provides the streamed data. + * @param delimiter The delimiter used to separate elements in the stream. + */ + public Stream(Class valueType, Reader reader, String delimiter) { + this.scanner = new Scanner(reader).useDelimiter(delimiter); + this.valueType = valueType; + } + + /** + * Returns an iterator over the elements in this stream that blocks during iteration when the next object is + * not yet available. + * + * @return An iterator that can be used to traverse the elements in the stream. + */ + @Override + public Iterator iterator() { + return new Iterator() { + /** + * Returns {@code true} if there are more elements in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return {@code true} if there are more elements, {@code false} otherwise. + */ + @Override + public boolean hasNext() { + return scanner.hasNext(); + } + + /** + * Returns the next element in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return The next element in the stream. + * @throws NoSuchElementException If there are no more elements in the stream. + */ + @Override + public T next() { + if (!scanner.hasNext()) { + throw new NoSuchElementException(); + } else { + try { + T parsedResponse = ObjectMappers.JSON_MAPPER.readValue( + scanner.next().trim(), valueType); + return parsedResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + /** + * Removing elements from {@code Stream} is not supported. + * + * @throws UnsupportedOperationException Always, as removal is not supported. + */ + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Suppliers.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Suppliers.java new file mode 100644 index 00000000..d3ab5e53 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Suppliers.java @@ -0,0 +1,23 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.core; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +public final class Suppliers { + private Suppliers() {} + + public static Supplier memoize(Supplier delegate) { + AtomicReference value = new AtomicReference<>(); + return () -> { + T val = value.get(); + if (val == null) { + val = value.updateAndGet(cur -> cur == null ? Objects.requireNonNull(delegate.get()) : cur); + } + return val; + }; + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/BadRequestError.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/BadRequestError.java new file mode 100644 index 00000000..4517200d --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/BadRequestError.java @@ -0,0 +1,34 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.errors; + +import com.skyflow.generated.auth.rest.core.ApiClientApiException; +import okhttp3.Response; + +import java.util.Map; + +public final class BadRequestError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final Map body; + + public BadRequestError(Map body) { + super("BadRequestError", 400, body); + this.body = body; + } + + public BadRequestError(Map body, Response rawResponse) { + super("BadRequestError", 400, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @Override + public Map body() { + return this.body; + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java new file mode 100644 index 00000000..2e1c45d2 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java @@ -0,0 +1,15 @@ +package com.skyflow.generated.auth.rest.errors; + +public enum HttpStatus { + BAD_REQUEST("Bad Request"); + + private final String httpStatus; + + HttpStatus(String httpStatus) { + this.httpStatus = httpStatus; + } + + public String getHttpStatus() { + return httpStatus; + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/NotFoundError.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/NotFoundError.java new file mode 100644 index 00000000..60a1771c --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/NotFoundError.java @@ -0,0 +1,34 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.errors; + +import com.skyflow.generated.auth.rest.core.ApiClientApiException; +import okhttp3.Response; + +import java.util.Map; + +public final class NotFoundError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final Map body; + + public NotFoundError(Map body) { + super("NotFoundError", 404, body); + this.body = body; + } + + public NotFoundError(Map body, Response rawResponse) { + super("NotFoundError", 404, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @Override + public Map body() { + return this.body; + } +} diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/UnauthorizedError.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/UnauthorizedError.java new file mode 100644 index 00000000..42f1c624 --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/UnauthorizedError.java @@ -0,0 +1,34 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.errors; + +import com.skyflow.generated.auth.rest.core.ApiClientApiException; +import okhttp3.Response; + +import java.util.Map; + +public final class UnauthorizedError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final Map body; + + public UnauthorizedError(Map body) { + super("UnauthorizedError", 401, body); + this.body = body; + } + + public UnauthorizedError(Map body, Response rawResponse) { + super("UnauthorizedError", 401, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @Override + public Map body() { + return this.body; + } +} diff --git a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncAuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java similarity index 84% rename from src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncAuthenticationClient.java rename to common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java index 43ffab73..c742b239 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncAuthenticationClient.java +++ b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java @@ -1,12 +1,13 @@ /** * This file was auto-generated by Fern from our API Definition. */ -package com.skyflow.generated.rest.resources.authentication; +package com.skyflow.generated.auth.rest.resources.authentication; + +import com.skyflow.generated.auth.rest.core.ClientOptions; +import com.skyflow.generated.auth.rest.core.RequestOptions; +import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest; +import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.authentication.requests.V1GetAuthTokenRequest; -import com.skyflow.generated.rest.types.V1GetAuthTokenResponse; import java.util.concurrent.CompletableFuture; public class AsyncAuthenticationClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncRawAuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncRawAuthenticationClient.java similarity index 82% rename from src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncRawAuthenticationClient.java rename to common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncRawAuthenticationClient.java index eca4ab90..56a47dc0 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncRawAuthenticationClient.java +++ b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncRawAuthenticationClient.java @@ -1,33 +1,22 @@ /** * This file was auto-generated by Fern from our API Definition. */ -package com.skyflow.generated.rest.resources.authentication; +package com.skyflow.generated.auth.rest.resources.authentication; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.errors.BadRequestError; -import com.skyflow.generated.rest.errors.NotFoundError; -import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.authentication.requests.V1GetAuthTokenRequest; -import com.skyflow.generated.rest.types.V1GetAuthTokenResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import com.skyflow.generated.auth.rest.core.*; +import com.skyflow.generated.auth.rest.errors.BadRequestError; +import com.skyflow.generated.auth.rest.errors.NotFoundError; +import com.skyflow.generated.auth.rest.errors.UnauthorizedError; +import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest; +import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; +import java.util.Map; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawAuthenticationClient { protected final ClientOptions clientOptions; @@ -88,17 +77,20 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue( + responseBodyString, new TypeReference>() {}), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue( + responseBodyString, new TypeReference>() {}), response)); return; case 404: future.completeExceptionally(new NotFoundError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue( + responseBodyString, new TypeReference>() {}), response)); return; } diff --git a/src/main/java/com/skyflow/generated/rest/resources/authentication/AuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AuthenticationClient.java similarity index 82% rename from src/main/java/com/skyflow/generated/rest/resources/authentication/AuthenticationClient.java rename to common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AuthenticationClient.java index 662bfb3d..a0ba860a 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/authentication/AuthenticationClient.java +++ b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AuthenticationClient.java @@ -1,12 +1,12 @@ /** * This file was auto-generated by Fern from our API Definition. */ -package com.skyflow.generated.rest.resources.authentication; +package com.skyflow.generated.auth.rest.resources.authentication; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.authentication.requests.V1GetAuthTokenRequest; -import com.skyflow.generated.rest.types.V1GetAuthTokenResponse; +import com.skyflow.generated.auth.rest.core.ClientOptions; +import com.skyflow.generated.auth.rest.core.RequestOptions; +import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest; +import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse; public class AuthenticationClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/authentication/RawAuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/RawAuthenticationClient.java similarity index 78% rename from src/main/java/com/skyflow/generated/rest/resources/authentication/RawAuthenticationClient.java rename to common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/RawAuthenticationClient.java index 3d242eff..6c52c048 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/authentication/RawAuthenticationClient.java +++ b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/RawAuthenticationClient.java @@ -1,29 +1,20 @@ /** * This file was auto-generated by Fern from our API Definition. */ -package com.skyflow.generated.rest.resources.authentication; +package com.skyflow.generated.auth.rest.resources.authentication; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.errors.BadRequestError; -import com.skyflow.generated.rest.errors.NotFoundError; -import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.authentication.requests.V1GetAuthTokenRequest; -import com.skyflow.generated.rest.types.V1GetAuthTokenResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import com.skyflow.generated.auth.rest.core.*; +import com.skyflow.generated.auth.rest.errors.BadRequestError; +import com.skyflow.generated.auth.rest.errors.NotFoundError; +import com.skyflow.generated.auth.rest.errors.UnauthorizedError; +import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest; +import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; +import java.util.Map; public class RawAuthenticationClient { protected final ClientOptions clientOptions; @@ -79,13 +70,19 @@ public ApiClientHttpResponse authenticationServiceGetAut switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue( + responseBodyString, new TypeReference>() {}), + response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue( + responseBodyString, new TypeReference>() {}), + response); case 404: throw new NotFoundError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue( + responseBodyString, new TypeReference>() {}), + response); } } catch (JsonProcessingException ignored) { // unable to map error response, throwing generic error diff --git a/src/main/java/com/skyflow/generated/rest/resources/authentication/requests/V1GetAuthTokenRequest.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/requests/V1GetAuthTokenRequest.java similarity index 96% rename from src/main/java/com/skyflow/generated/rest/resources/authentication/requests/V1GetAuthTokenRequest.java rename to common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/requests/V1GetAuthTokenRequest.java index 182952bc..382c5431 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/authentication/requests/V1GetAuthTokenRequest.java +++ b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/requests/V1GetAuthTokenRequest.java @@ -1,22 +1,17 @@ /** * This file was auto-generated by Fern from our API Definition. */ -package com.skyflow.generated.rest.resources.authentication.requests; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +package com.skyflow.generated.auth.rest.resources.authentication.requests; + +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.auth.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1GetAuthTokenRequest.Builder.class) diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/types/V1GetAuthTokenResponse.java b/common/src/main/java/com/skyflow/generated/auth/rest/types/V1GetAuthTokenResponse.java new file mode 100644 index 00000000..3db2f22b --- /dev/null +++ b/common/src/main/java/com/skyflow/generated/auth/rest/types/V1GetAuthTokenResponse.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.auth.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.auth.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1GetAuthTokenResponse.Builder.class) +public final class V1GetAuthTokenResponse { + private final Optional accessToken; + + private final Optional tokenType; + + private final Map additionalProperties; + + private V1GetAuthTokenResponse( + Optional accessToken, Optional tokenType, Map additionalProperties) { + this.accessToken = accessToken; + this.tokenType = tokenType; + this.additionalProperties = additionalProperties; + } + + /** + * @return AccessToken. + */ + @JsonProperty("accessToken") + public Optional getAccessToken() { + return accessToken; + } + + /** + * @return TokenType : Bearer. + */ + @JsonProperty("tokenType") + public Optional getTokenType() { + return tokenType; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1GetAuthTokenResponse && equalTo((V1GetAuthTokenResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1GetAuthTokenResponse other) { + return accessToken.equals(other.accessToken) && tokenType.equals(other.tokenType); + } + + @Override + public int hashCode() { + return Objects.hash(this.accessToken, this.tokenType); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional accessToken = Optional.empty(); + + private Optional tokenType = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1GetAuthTokenResponse other) { + accessToken(other.getAccessToken()); + tokenType(other.getTokenType()); + return this; + } + + /** + *

AccessToken.

+ */ + @JsonSetter(value = "accessToken", nulls = Nulls.SKIP) + public Builder accessToken(Optional accessToken) { + this.accessToken = accessToken; + return this; + } + + public Builder accessToken(String accessToken) { + this.accessToken = Optional.ofNullable(accessToken); + return this; + } + + /** + *

TokenType : Bearer.

+ */ + @JsonSetter(value = "tokenType", nulls = Nulls.SKIP) + public Builder tokenType(Optional tokenType) { + this.tokenType = tokenType; + return this; + } + + public Builder tokenType(String tokenType) { + this.tokenType = Optional.ofNullable(tokenType); + return this; + } + + public V1GetAuthTokenResponse build() { + return new V1GetAuthTokenResponse(accessToken, tokenType, additionalProperties); + } + } +} diff --git a/common/src/main/java/com/skyflow/logs/ErrorLogs.java b/common/src/main/java/com/skyflow/logs/ErrorLogs.java new file mode 100644 index 00000000..0028a5c6 --- /dev/null +++ b/common/src/main/java/com/skyflow/logs/ErrorLogs.java @@ -0,0 +1,185 @@ +package com.skyflow.logs; + +public enum ErrorLogs { + // Client initialization + VAULT_CONFIG_EXISTS("Vault config with vault ID %s1 already exists."), + VAULT_CONFIG_DOES_NOT_EXIST("Vault config with vault ID %s1 doesn't exist."), + VAULT_ID_IS_REQUIRED("Invalid vault config. Vault ID is required."), + EMPTY_VAULT_ID("Invalid vault config. Vault ID can not be empty."), + CLUSTER_ID_IS_REQUIRED("Invalid vault config. Cluster ID is required."), + EMPTY_CLUSTER_ID("Invalid vault config. Cluster ID can not be empty."), + EITHER_VAULT_URL_OR_CLUSTER_ID_REQUIRED("Invalid vault config. At least one of \"clusterId\" or \"vaultURL\" must be provided."), + CONNECTION_CONFIG_EXISTS("Connection config with connection ID %s1 already exists."), + CONNECTION_CONFIG_DOES_NOT_EXIST("Connection config with connection ID %s1 doesn't exist."), + CONNECTION_ID_IS_REQUIRED("Invalid connection config. Connection ID is required."), + EMPTY_CONNECTION_ID("Invalid connection config. Connection ID can not be empty."), + CONNECTION_URL_IS_REQUIRED("Invalid connection config. Connection URL is required."), + EMPTY_CONNECTION_URL("Invalid connection config. Connection URL can not be empty."), + INVALID_CONNECTION_URL("Invalid connection config. Connection URL is not a valid URL."), + MULTIPLE_TOKEN_GENERATION_MEANS_PASSED("Invalid credentials. Only one of 'path', 'credentialsString', 'token' or 'apiKey' is allowed."), + NO_TOKEN_GENERATION_MEANS_PASSED("Invalid credentials. Any one of 'path', 'credentialsString', 'token' or 'apiKey' is required."), + EMPTY_CREDENTIALS_PATH("Invalid credentials. Credentials path can not be empty."), + EMPTY_CREDENTIALS_STRING("Invalid credentials. Credentials string can not be empty."), + EMPTY_TOKEN_VALUE("Invalid credentials. Token can not be empty."), + EMPTY_API_KEY_VALUE("Invalid credentials. Api key can not be empty."), + INVALID_API_KEY("Invalid credentials. Api key is invalid."), + EMPTY_ROLES("Invalid credentials. Roles can not be empty."), + EMPTY_OR_NULL_ROLE_IN_ROLES("Invalid credentials. Role can not be null or empty in roles at index %s1."), + EMPTY_OR_NULL_CONTEXT("Invalid credentials. Context can not be empty."), + INVALID_CONTEXT_TYPE("Invalid credentials. Context must be a String or Map."), + INVALID_CONTEXT_MAP_KEY("Invalid credentials. Context map key '%s1' contains invalid characters."), + EMPTY_VAULT_URL("Invalid vault config. Vault URL can not be empty."), + INVALID_VAULT_URL_FORMAT("Invalid vault config. Vault URL format is incorrect"), + + // Bearer token generation + INVALID_BEARER_TOKEN("Bearer token is invalid or expired."), + INVALID_CREDENTIALS_FILE("Credentials file is either null or an invalid file."), + INVALID_CREDENTIALS_STRING("Credentials string is either null or empty."), + INVALID_CREDENTIALS_FILE_FORMAT("Credentials file is not in a valid JSON format."), + CREDENTIALS_FILE_NOT_FOUND("Credentials file not found at specified path."), + INVALID_CREDENTIALS_STRING_FORMAT("Credentials string is not in a valid JSON string format."), + PRIVATE_KEY_IS_REQUIRED("Private key is required."), + CLIENT_ID_IS_REQUIRED("Client ID is required."), + KEY_ID_IS_REQUIRED("Key ID is required."), + TOKEN_URI_IS_REQUIRED("Token URI is required."), + INVALID_TOKEN_URI("Invalid value for token URI in credentials."), + JWT_INVALID_FORMAT("Private key is not in a valid format."), + INVALID_ALGORITHM("Algorithm for parsing private key is invalid or does not exist."), + INVALID_KEY_SPEC("Unable to parse RSA private key."), + BEARER_TOKEN_REJECTED("Bearer token request resulted in failure."), + SIGNED_DATA_TOKENS_REJECTED("Signed data tokens request resulted in failure."), + + // Vault api interfaces + TABLE_IS_REQUIRED("Invalid %s1 request. Table is required."), + EMPTY_TABLE_NAME("Invalid %s1 request. Table name can not be empty."), + VALUES_IS_REQUIRED("Invalid %s1 request. Values are required."), + EMPTY_VALUES("Invalid %s1 request. Values can not be empty."), + RECORDS_IS_REQUIRED("Invalid %s1 request. Records are required."), + EMPTY_RECORDS("Invalid %s1 request. Records can not be empty."), + INVALID_RECORD("Invalid %s1 request. Invalid record. Specify a valid record."), + RECORD_SIZE_EXCEED("Maximum number of records exceeded. The limit is 10000."), + TOKENS_SIZE_EXCEED("Maximum number of tokens exceeded. The limit is 10000."), + EMPTY_OR_NULL_VALUE_IN_VALUES("Invalid %s1 request. Value can not be null or empty in values for key \"%s2\"."), + EMPTY_OR_NULL_KEY_IN_VALUES("Invalid %s1 request. Key can not be null or empty in values"), + EMPTY_UPSERT("Invalid %s1 request. Upsert can not be empty."), + EMPTY_UPSERT_VALUES("Invalid %s1 request. Upsert values can not be empty."), + HOMOGENOUS_NOT_SUPPORTED_WITH_UPSERT("Invalid %s1 request. Homogenous is not supported when upsert is passed."), + TOKENS_NOT_ALLOWED_WITH_TOKEN_MODE_DISABLE("Invalid %s1 request. Tokens are not allowed when tokenMode is DISABLE."), + TOKENS_REQUIRED_WITH_TOKEN_MODE("Invalid %s1 request. Tokens are required when tokenMode is %s2."), + EMPTY_TOKENS("Invalid %s1 request. Tokens can not be empty."), + EMPTY_OR_NULL_VALUE_IN_TOKENS("Invalid %s1 request. Value can not be null or empty in tokens for key \"%s2\"."), + EMPTY_OR_NULL_KEY_IN_TOKENS("Invalid %s1 request. Key can not be null or empty in tokens."), + INSUFFICIENT_TOKENS_PASSED_FOR_TOKEN_MODE_ENABLE_STRICT("Invalid %s1 request. For tokenMode as ENABLE_STRICT, tokens should be passed for all fields."), + MISMATCH_OF_FIELDS_AND_TOKENS("Invalid %s1 request. Keys for values and tokens are not matching."), + INSERT_RECORDS_REJECTED("Insert request resulted in failure."), + DETOKENIZE_DATA_REQUIRED("Invalid %s1 request. Detokenize data is required."), + EMPTY_DETOKENIZE_DATA("Invalid %s1 request. Detokenize data can not be empty."), + EMPTY_OR_NULL_TOKEN_IN_DETOKENIZE_DATA("Invalid %s1 request. Token can not be null or empty in detokenize data at index %s2."), + REDACTION_IS_REQUIRED("Invalid %s1 request. Redaction is required."), + DETOKENIZE_REQUEST_REJECTED("Detokenize request resulted in failure."), + DETOKENIZE_REQUEST_NULL("Invalid %s1 request. Detokenize request can not be null."), + + NULL_TOKEN_REDACTION_GROUP_OBJECT("Invalid %s1 request. Token Redaction group object can not be null or empty."), + + NULL_REDACTION_IN_TOKEN_GROUP("Invalid %s1 request. Redaction can not be null in token redaction group"), + + NULL_TOKEN_GROUP_NAME_IN_TOKEN_GROUP("Invalid %s1 request. Token group name can not be null in token redaction group"), + + EMPTY_OR_NULL_REDACTION_IN_TOKEN_GROUP("Invalid %s1 request. Redaction can not be null or empty in token redaction group"), + IDS_IS_REQUIRED("Invalid %s1 request. Ids are required."), + EMPTY_IDS("Invalid %s1 request. Ids can not be empty."), + EMPTY_OR_NULL_ID_IN_IDS("Invalid %s1 request. Id can not be null or empty in ids at index %s2."), + EMPTY_FIELDS("Invalid %s1 request. Fields can not be empty."), + EMPTY_OR_NULL_FIELD_IN_FIELDS("Invalid %s1 request. Field can not be null or empty in fields at index %s2."), + TOKENIZATION_NOT_SUPPORTED_WITH_REDACTION("Invalid %s1 request. Return tokens is not supported when redaction is applied."), + TOKENIZATION_SUPPORTED_ONLY_WITH_IDS("Invalid %s1 request. Return tokens is not supported when column name and values are passed."), + EMPTY_OFFSET("Invalid %s1 request. Offset can not be empty."), + EMPTY_LIMIT("Invalid %s1 request. Limit can not be empty."), + NEITHER_IDS_NOR_COLUMN_NAME_PASSED("Invalid %s1 request. Neither ids nor column name and values are passed."), + BOTH_IDS_AND_COLUMN_NAME_PASSED("Invalid %s1 request. Both ids and column name and values are passed."), + COLUMN_NAME_IS_REQUIRED("Invalid %s1 request. Column name is required when column values are passed."), + EMPTY_COLUMN_NAME("Invalid %s1 request. Column name can not be empty."), + COLUMN_VALUES_IS_REQUIRED_GET("Invalid %s1 request. Column values are required when column name is passed."), + EMPTY_COLUMN_VALUES("Invalid %s1 request. Column values can not be empty."), + EMPTY_OR_NULL_COLUMN_VALUE_IN_COLUMN_VALUES("Invalid %s1 request. Column value can not by null or empty in column values at index %s2."), + GET_REQUEST_REJECTED("Get request resulted in failure."), + DATA_IS_REQUIRED("Invalid %s1 request. Data is required."), + EMPTY_DATA("Invalid %s1 request. Data can not be empty."), + SKYFLOW_ID_IS_REQUIRED("Invalid %s1 request. Skyflow Id is required."), + INVALID_SKYFLOW_ID_TYPE("Invalid %s1 request. Skyflow Id should of type String."), + EMPTY_SKYFLOW_ID("Invalid %s1 request. Skyflow Id can not be empty."), + UPDATE_REQUEST_REJECTED("Update request resulted in failure."), + QUERY_IS_REQUIRED("Invalid %s1 request. Query is required."), + EMPTY_QUERY("Invalid %s1 request. Query can not be empty."), + QUERY_REQUEST_REJECTED("Query request resulted in failure."), + COLUMN_VALUES_IS_REQUIRED_TOKENIZE("Invalid %s1 request. ColumnValues are required."), + EMPTY_OR_NULL_COLUMN_GROUP_IN_COLUMN_VALUES("Invalid %s1 request. Column group can not be null or empty in column values at index %s2."), + TOKENIZE_REQUEST_REJECTED("Tokenize request resulted in failure."), + TOKENIZE_REQUEST_NULL("Invalid %s1 request. Tokenize request can not be null."), + EMPTY_TOKENIZE_DATA("Invalid %s1 request. Tokenize data can not be empty."), + TOKENIZE_RECORD_NULL("Invalid %s1 request. TokenizeRecord in list can not be null."), + EMPTY_VALUE_IN_TOKENIZE_RECORD("Invalid %s1 request. Value in TokenizeRecord can not be null or empty."), + EMPTY_TOKEN_GROUP_NAMES_IN_TOKENIZE_RECORD("Invalid %s1 request. TokenGroupNames in TokenizeRecord can not be null or empty."), + EMPTY_TOKEN_GROUP_NAME_IN_TOKENIZE_RECORD("Invalid %s1 request. Token group name in TokenizeRecord can not be null or empty at index %s2."), + TOKENIZE_DATA_SIZE_EXCEED("Maximum number of tokenize records exceeded. The limit is 10000."), + DELETE_REQUEST_REJECTED("Delete request resulted in failure."), + DELETE_TOKENS_REQUEST_NULL("Invalid %s1 request. DeleteTokens request can not be null."), + EMPTY_DELETE_TOKENS_DATA("Invalid %s1 request. Delete tokens data can not be empty."), + EMPTY_OR_NULL_TOKEN_IN_DELETE_TOKENS_DATA("Invalid %s1 request. Token can not be null or empty in delete tokens data at index %s2."), + DELETE_TOKENS_SIZE_EXCEED("Maximum number of tokens exceeded. The limit is 10000."), + + // invoke connection interface + INVOKE_CONNECTION_INVALID_CONNECTION_URL("Invalid %s1 request. Connection URL is not a valid URL."), + EMPTY_REQUEST_HEADERS("Invalid %s1 request. Request headers can not be empty."), + INVALID_REQUEST_HEADERS("Invalid %s1 request. Request header can not be null or empty in request headers."), + EMPTY_PATH_PARAMS("Invalid %s1 request. Path params can not be empty."), + INVALID_PATH_PARAM("Invalid %s1 request. Path parameter can not be null or empty in path params."), + EMPTY_QUERY_PARAMS("Invalid %s1 request. Query params can not be empty."), + INVALID_QUERY_PARAM("Invalid %s1 request. Query parameter can not be null or empty in query params."), + EMPTY_REQUEST_BODY("Invalid %s1 request. Request body can not be empty."), + INVALID_REQUEST_BODY("Invalid %s1 request. Request body can not be empty."), + INVOKE_CONNECTION_REQUEST_REJECTED("Invoke connection request resulted in failure."), + + // File upload interface + COLUMN_NAME_IS_REQUIRED_FILE_UPLOAD("Invalid %s1 request. Column name is required."), + EMPTY_COLUMN_NAME_FILE_UPLOAD("Invalid %s1 request. Column name can not be empty."), + FILE_IS_REQUIRED("Invalid %s1 request. File is required."), + EMPTY_FILE("Invalid %s1 request. File can not be empty."), + INVALID_FILE_TYPE("Invalid %s1 request. File should be of type java.io.File"), + MISSING_FILE_SOURCE_IN_UPLOAD_FILE("Invalid %s1 request. Provide exactly one of filePath, base64, or fileObject."), + UPLOAD_FILE_REQUEST_REJECTED("Upload file request resulted in failure."), + + // detect interface + INVALID_TEXT_IN_DEIDENTIFY("Invalid %s1 request. The text field is required and must be a non-empty string. Specify a valid text."), + DEIDENTIFY_TEXT_REQUEST_REJECTED("DeIdentify text request resulted in failure."), + INVALID_TEXT_IN_REIDENTIFY("Invalid %s1 request. The text field is required and must be a non-empty string. Specify a valid text."), + REIDENTIFY_TEXT_REQUEST_REJECTED("ReIdentify text request resulted in failure."), + DEIDENTIFY_FILE_REQUEST_REJECTED("DeIdentify file request resulted in failure."), + GET_DETECT_RUN_REQUEST_REJECTED("Get detect run request resulted in failure."), + INVALID_NULL_FILE_IN_DEIDENTIFY_FILE("Invalid %s1 request. The file field is required and must not be null. Specify a valid file."), + FILE_NOT_FOUND_TO_DEIDENTIFY("Invalid %s1 request. The file field is required and must not be empty. Specify a valid file."), + FILE_NOT_READABLE_TO_DEIDENTIFY("Invalid %s1 request. The file is not readable. Please check the file permissions or path."), + INVALID_PIXEL_DENSITY_TO_DEIDENTIFY_FILE("Invalid %s1 request. Pixel density must be a positive integer greater than 0. Specify a valid pixel density."), + INVALID_MAX_RESOLUTION("Invalid %s1 request. Max resolution must be a positive integer greater than 0. Specify a valid max resolution."), + INVALID_BLEEP_TO_DEIDENTIFY_AUDIO("Invalid %s1 request. Specify a valid bleep as AudioBleep"), + OUTPUT_DIRECTORY_NOT_FOUND("Invalid %s1 request. The output directory does not exist. Please specify a valid output directory."), + INVALID_PERMISSIONS_FOR_OUTPUT_DIRECTORY("Invalid %s1 request. The output directory is not writable. Please check the permissions or specify a valid output directory."), + EMPTY_FILE_AND_FILE_PATH_IN_DEIDENTIFY_FILE("Invalid %s1 request. The file and file path fields are both empty. Specify a valid file object or file path."), + + UNEXPECTED_ERROR_DURING_BATCH_PROCESSING("Unexpected error occurred during batch processing. Error: %s1"), + + PROCESSING_ERROR_RESPONSE("Processing error response."), + TABLE_SPECIFIED_AT_BOTH_PLACE("Invalid %s1 request. Table name cannot be specified at both the request and record levels. Please specify the table name at only one place."), + TABLE_NOT_SPECIFIED_AT_BOTH_PLACE("Invalid %s1 request. Table name is missing. Table name should be specified at one place either at the request level or record level. Please specify the table name at one place."), + UPSERT_TABLE_REQUEST_AT_RECORD_LEVEL("Invalid %s1 request. Table name should be present at each record level when upsert is present at record level."), + UPSERT_TABLE_REQUEST_AT_REQUEST_LEVEL("Invalid %s1 request. Upsert should be present at each record level when table name is present at record level."); + private final String log; + + ErrorLogs(String log) { + this.log = log; + } + + public final String getLog() { + return log; + } +} diff --git a/common/src/main/java/com/skyflow/logs/InfoLogs.java b/common/src/main/java/com/skyflow/logs/InfoLogs.java new file mode 100644 index 00000000..6d6a8211 --- /dev/null +++ b/common/src/main/java/com/skyflow/logs/InfoLogs.java @@ -0,0 +1,131 @@ +package com.skyflow.logs; + +public enum InfoLogs { + // Client initialization + CLIENT_INITIALIZED("Initialized skyflow client."), + VALIDATING_VAULT_CONFIG("Validating vault config."), + VALIDATING_CONNECTION_CONFIG("Validating connection config."), + UNABLE_TO_GENERATE_SDK_METRIC("Unable to generate %s1 metric."), + VAULT_CONTROLLER_INITIALIZED("Initialized vault controller with vault ID %s1."), + DETECT_CONTROLLER_INITIALIZED("Initialized detect controller with vault ID %s1."), + CONNECTION_CONTROLLER_INITIALIZED("Initialized connection controller with connection ID %s1."), + LOGGER_SETUP_DONE("Set up logger."), + CURRENT_LOG_LEVEL("Current log level is %s1."), + + // Bearer token generation + EMPTY_BEARER_TOKEN("Bearer token is empty."), + BEARER_TOKEN_EXPIRED("Bearer token is expired."), + GET_BEARER_TOKEN_TRIGGERED("getBearerToken method triggered."), + GET_BEARER_TOKEN_SUCCESS("Bearer token generated."), + GET_SIGNED_DATA_TOKENS_TRIGGERED("getSignedDataTokens method triggered."), + GET_SIGNED_DATA_TOKEN_SUCCESS("Signed data tokens generated."), + REUSE_BEARER_TOKEN("Reusing bearer token."), + USE_CLIENT_PROVIDED_BEARER_TOKEN("Using bearer token provided by client."), + USE_API_KEY("Using api key."), + REUSE_API_KEY("Reusing api key."), + GENERATE_BEARER_TOKEN_FROM_CREDENTIALS_TRIGGERED("generateBearerTokenFromCredentials method triggered."), + GENERATE_BEARER_TOKEN_FROM_CREDENTIALS_STRING_TRIGGERED("generateBearerTokenFromCredentialString method triggered."), + GENERATE_SIGNED_TOKENS_FROM_CREDENTIALS_FILE_TRIGGERED("generateSignedTokensFromCredentialsFile method triggered."), + GENERATE_SIGNED_TOKENS_FROM_CREDENTIALS_STRING_TRIGGERED("generateSignedTokensFromCredentialsString method triggered."), + + // Insert interface + INSERT_TRIGGERED("Insert method triggered."), + VALIDATE_INSERT_REQUEST("Validating insert request."), + INSERT_REQUEST_RESOLVED("Insert request resolved."), + INSERT_SUCCESS("Data inserted."), + + // Detokenize interface + DETOKENIZE_TRIGGERED("Detokenize method triggered."), + VALIDATE_DETOKENIZE_REQUEST("Validating detokenize request."), + DETOKENIZE_REQUEST_RESOLVED("Detokenize request resolved."), + DETOKENIZE_PARTIAL_SUCCESS("Data detokenized partially."), + DETOKENIZE_SUCCESS("Data detokenized."), + + // Get interface + GET_TRIGGERED("Get method triggered."), + VALIDATE_GET_REQUEST("Validating get request."), + GET_REQUEST_RESOLVED("Get request resolved."), + GET_SUCCESS("Data revealed."), + + // Update interface + UPDATE_TRIGGERED("Update method triggered."), + VALIDATE_UPDATE_REQUEST("Validating update request."), + UPDATE_REQUEST_RESOLVED("Update request resolved."), + UPDATE_SUCCESS("Data updated."), + + // Delete interface + DELETE_TRIGGERED("Delete method triggered."), + VALIDATING_DELETE_REQUEST("Validating delete request."), + DELETE_REQUEST_RESOLVED("Delete request resolved."), + DELETE_SUCCESS("Data deleted."), + + // Delete Tokens interface + DELETE_TOKENS_TRIGGERED("DeleteTokens method triggered."), + VALIDATE_DELETE_TOKENS_REQUEST("Validating delete tokens request."), + DELETE_TOKENS_REQUEST_RESOLVED("DeleteTokens request resolved."), + DELETE_TOKENS_SUCCESS("Tokens deleted."), + + // Query interface + QUERY_TRIGGERED("Query method triggered."), + VALIDATING_QUERY_REQUEST("Validating query request."), + QUERY_REQUEST_RESOLVED("Query request resolved."), + QUERY_SUCCESS("Query executed."), + + // Tokenize interface + TOKENIZE_TRIGGERED("Tokenize method triggered."), + VALIDATING_TOKENIZE_REQUEST("Validating tokenize request."), + TOKENIZE_REQUEST_RESOLVED("Tokenize request resolved."), + TOKENIZE_SUCCESS("Data tokenized."), + + + // Invoke connection interface + INVOKE_CONNECTION_TRIGGERED("Invoke connection method triggered."), + VALIDATING_INVOKE_CONNECTION_REQUEST("Validating invoke connection request."), + INVOKE_CONNECTION_REQUEST_RESOLVED("Invoke connection request resolved."), + + // detect + VALIDATE_DEIDENTIFY_TEXT_REQUEST("Validating deidentify text request."), + DEIDENTIFY_TEXT_SUCCESS("Text data de-identified."), + DEIDENTIFY_TEXT_TRIGGERED("DeIdentify text method triggered."), + DEIDENTIFY_TEXT_REQUEST_RESOLVED("DeIdentify text request resolved."), + VALIDATE_REIDENTIFY_TEXT_REQUEST("Validating reidentify text request."), + REIDENTIFY_TEXT_TRIGGERED("ReIdentify text method triggered."), + REIDENTIFY_TEXT_REQUEST_RESOLVED("ReIdentify text request resolved."), + DEIDENTIFY_FILE_TRIGGERED("DeIdentify file method triggered."), + VALIDATE_DEIDENTIFY_FILE_REQUEST("Validating deidentify file request."), + DEIDENTIFY_FILE_REQUEST_RESOLVED("DeIdentify file request resolved."), + DEIDENTIFY_FILE_SUCCESS("File deidentified successfully."), + GET_DETECT_RUN_TRIGGERED("Get detect run method triggered."), + VALIDATE_GET_DETECT_RUN_REQUEST("Validating get detect run request."), + REIDENTIFY_TEXT_SUCCESS("Text data re-identified."), + + // File upload interface + FILE_UPLOAD_TRIGGERED("File upload method triggered."), + VALIDATING_FILE_UPLOAD_REQUEST("Validating file upload request."), + FILE_UPLOAD_REQUEST_RESOLVED("File upload request resolved."), + FILE_UPLOAD_SUCCESS("File uploaded successfully."), + + PROCESSING_BATCHES("Processing batch"), + + // Deprecation warnings — v2 backward compat + DEPRECATED_SKYFLOW_ID_KEY("[DEPRECATED] Response key 'skyflow_id' is deprecated and will be removed in an upcoming release. Use 'skyflowId' instead."), + DEPRECATED_SKYFLOW_ID_REQUEST_KEY("[DEPRECATED] Request data key 'skyflow_id' is deprecated and will be removed in an upcoming release. Use 'skyflowId' instead."), + DEPRECATED_DOWNLOAD_URL("[DEPRECATED] Method 'downloadURL()' is deprecated and will be removed in an upcoming release. Use 'downloadUrl()' instead."), + DEPRECATED_GET_BYOT("[DEPRECATED] Method 'getBYOT()' is deprecated and will be removed in an upcoming release. Use 'getByot()' instead."), + DEPRECATED_UPDATE_LOG_LEVEL("[DEPRECATED] Method 'updateLogLevel()' is deprecated and will be removed in an upcoming release. Use 'setLogLevel()' instead."), + DEPRECATED_CREDENTIAL_CLIENT_ID("[DEPRECATED] Credential field 'clientID' is deprecated and will be removed in an upcoming release. Use 'clientId' instead."), + DEPRECATED_CREDENTIAL_KEY_ID("[DEPRECATED] Credential field 'keyID' is deprecated and will be removed in an upcoming release. Use 'keyId' instead."), + DEPRECATED_CREDENTIAL_TOKEN_URI("[DEPRECATED] Credential field 'tokenURI' is deprecated and will be removed in an upcoming release. Use 'tokenUri' instead.") + ; + + + private final String log; + + InfoLogs(String log) { + this.log = log; + } + + public final String getLog() { + return log; + } +} diff --git a/common/src/main/java/com/skyflow/logs/WarningLogs.java b/common/src/main/java/com/skyflow/logs/WarningLogs.java new file mode 100644 index 00000000..5f80a728 --- /dev/null +++ b/common/src/main/java/com/skyflow/logs/WarningLogs.java @@ -0,0 +1,19 @@ +package com.skyflow.logs; + +public enum WarningLogs { + INVALID_BATCH_SIZE_PROVIDED("Invalid value for batch size provided, switching to default value."), + INVALID_CONCURRENCY_LIMIT_PROVIDED("Invalid value for concurrency limit provided, switching to default value."), + BATCH_SIZE_EXCEEDS_MAX_LIMIT("Provided batch size exceeds the maximum limit, switching to max limit."), + CONCURRENCY_EXCEEDS_MAX_LIMIT("Provided concurrency limit exceeds the maximum limit, switching to max limit.") + ; + + private final String log; + + WarningLogs(String log) { + this.log = log; + } + + public final String getLog() { + return log; + } +} diff --git a/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java b/common/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java similarity index 92% rename from src/main/java/com/skyflow/serviceaccount/util/BearerToken.java rename to common/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java index ad7cae30..317847e5 100644 --- a/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java +++ b/common/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java @@ -4,16 +4,16 @@ import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; -import com.skyflow.generated.rest.ApiClient; -import com.skyflow.generated.rest.ApiClientBuilder; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.resources.authentication.AuthenticationClient; -import com.skyflow.generated.rest.resources.authentication.requests.V1GetAuthTokenRequest; -import com.skyflow.generated.rest.types.V1GetAuthTokenResponse; +import com.skyflow.generated.auth.rest.ApiClient; +import com.skyflow.generated.auth.rest.ApiClientBuilder; +import com.skyflow.generated.auth.rest.core.ApiClientApiException; +import com.skyflow.generated.auth.rest.resources.authentication.AuthenticationClient; +import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest; +import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; -import com.skyflow.utils.Constants; -import com.skyflow.utils.Utils; +import com.skyflow.utils.BaseConstants; +import com.skyflow.utils.BaseUtils; import com.skyflow.utils.logger.LogUtil; import io.jsonwebtoken.Jwts; @@ -67,11 +67,11 @@ private static V1GetAuthTokenResponse generateBearerTokenFromCredentials( } } catch (JsonSyntaxException e) { LogUtil.printErrorLog(ErrorLogs.INVALID_CREDENTIALS_FILE_FORMAT.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), Utils.parameterizedString( + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseUtils.parameterizedString( ErrorMessage.FileInvalidJson.getMessage(), credentialsFile.getPath())); } catch (FileNotFoundException e) { LogUtil.printErrorLog(ErrorLogs.CREDENTIALS_FILE_NOT_FOUND.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), Utils.parameterizedString( + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseUtils.parameterizedString( ErrorMessage.FileNotFound.getMessage(), credentialsFile.getPath())); } } @@ -141,17 +141,17 @@ private static V1GetAuthTokenResponse getBearerTokenFromCredentials( throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MissingTokenUri.getMessage()); } - PrivateKey pvtKey = Utils.getPrivateKeyFromPem(privateKey.getAsString()); + PrivateKey pvtKey = BaseUtils.getPrivateKeyFromPem(privateKey.getAsString()); String signedUserJWT = getSignedToken( clientId.getAsString(), keyId.getAsString(), tokenUri.getAsString(), pvtKey, context ); - String basePath = Utils.getBaseURL(tokenUri.getAsString()); + String basePath = BaseUtils.getBaseURL(tokenUri.getAsString()); API_CLIENT_BUILDER.url(basePath); ApiClient apiClient = API_CLIENT_BUILDER.token("token").build(); AuthenticationClient authenticationApi = apiClient.authentication(); - V1GetAuthTokenRequest._FinalStage authTokenBuilder = V1GetAuthTokenRequest.builder().grantType(Constants.GRANT_TYPE).assertion(signedUserJWT); + V1GetAuthTokenRequest._FinalStage authTokenBuilder = V1GetAuthTokenRequest.builder().grantType(BaseConstants.GRANT_TYPE).assertion(signedUserJWT); if (roles != null) { String scopedRoles = getScopeUsingRoles(roles); diff --git a/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokenResponse.java b/common/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokenResponse.java similarity index 83% rename from src/main/java/com/skyflow/serviceaccount/util/SignedDataTokenResponse.java rename to common/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokenResponse.java index 3d35b541..c4618ae6 100644 --- a/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokenResponse.java +++ b/common/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokenResponse.java @@ -1,10 +1,10 @@ package com.skyflow.serviceaccount.util; import com.google.gson.Gson; -import com.skyflow.utils.Constants; +import com.skyflow.utils.BaseConstants; public class SignedDataTokenResponse { - private static final String PREFIX = Constants.SIGNED_DATA_TOKEN_PREFIX; + private static final String PREFIX = BaseConstants.SIGNED_DATA_TOKEN_PREFIX; private final String token; private final String signedToken; diff --git a/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokens.java b/common/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokens.java similarity index 97% rename from src/main/java/com/skyflow/serviceaccount/util/SignedDataTokens.java rename to common/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokens.java index b909e45b..630a0aee 100644 --- a/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokens.java +++ b/common/src/main/java/com/skyflow/serviceaccount/util/SignedDataTokens.java @@ -9,7 +9,7 @@ import com.skyflow.errors.SkyflowException; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; -import com.skyflow.utils.Utils; +import com.skyflow.utils.BaseUtils; import com.skyflow.utils.logger.LogUtil; import io.jsonwebtoken.Jwts; @@ -18,11 +18,7 @@ import java.io.FileReader; import java.io.IOException; import java.security.PrivateKey; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; public class SignedDataTokens { private final File credentialsFile; @@ -64,11 +60,11 @@ private static List generateSignedTokenFromCredentialsF } } catch (JsonSyntaxException e) { LogUtil.printErrorLog(ErrorLogs.INVALID_CREDENTIALS_FILE_FORMAT.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), Utils.parameterizedString( + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseUtils.parameterizedString( ErrorMessage.FileInvalidJson.getMessage(), credentialsFile.getPath())); } catch (FileNotFoundException e) { LogUtil.printErrorLog(ErrorLogs.CREDENTIALS_FILE_NOT_FOUND.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), Utils.parameterizedString( + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseUtils.parameterizedString( ErrorMessage.FileNotFound.getMessage(), credentialsFile.getPath())); } return responseToken; @@ -129,7 +125,7 @@ private static List generateSignedTokensFromCredentials LogUtil.printErrorLog(ErrorLogs.KEY_ID_IS_REQUIRED.getLog()); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MissingKeyId.getMessage()); } - PrivateKey pvtKey = Utils.getPrivateKeyFromPem(privateKey.getAsString()); + PrivateKey pvtKey = BaseUtils.getPrivateKeyFromPem(privateKey.getAsString()); signedDataTokens = getSignedToken( clientId.getAsString(), keyId.getAsString(), pvtKey, dataTokens, timeToLive, context); } catch (RuntimeException e) { diff --git a/src/main/java/com/skyflow/serviceaccount/util/Token.java b/common/src/main/java/com/skyflow/serviceaccount/util/Token.java similarity index 100% rename from src/main/java/com/skyflow/serviceaccount/util/Token.java rename to common/src/main/java/com/skyflow/serviceaccount/util/Token.java diff --git a/common/src/main/java/com/skyflow/utils/BaseConstants.java b/common/src/main/java/com/skyflow/utils/BaseConstants.java new file mode 100644 index 00000000..8aeb9f95 --- /dev/null +++ b/common/src/main/java/com/skyflow/utils/BaseConstants.java @@ -0,0 +1,34 @@ +package com.skyflow.utils; + +public class BaseConstants { + public static final String SDK_NAME= "Skyflow Java SDK "; + public static final String SDK_VERSION = "1.0.0"; + public static final String SDK_PREFIX = SDK_NAME + SDK_VERSION; + public static final String ORDER_ASCENDING = "ASCENDING"; + public static final String ENV_CREDENTIALS_KEY_NAME = "SKYFLOW_CREDENTIALS"; + public static final String SECURE_PROTOCOL = "https://"; + + public static final String V2_VAULT_DOMAIN = ".vault."; + public static final String V3_VAULT_DOMAIN = ".skyvault."; + public static final String DEV_DOMAIN = "skyflowapis.dev"; + public static final String STAGE_DOMAIN = "skyflowapis.tech"; + public static final String SANDBOX_DOMAIN = "skyflowapis-preview.com"; + public static final String PROD_DOMAIN = "skyflowapis.com"; + public static final String PKCS8_PRIVATE_HEADER = "-----BEGIN PRIVATE KEY-----"; + public static final String PKCS8_PRIVATE_FOOTER = "-----END PRIVATE KEY-----"; + public static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + public static final String SIGNED_DATA_TOKEN_PREFIX = "signed_token_"; + public static final String API_KEY_REGEX = "^sky-[a-zA-Z0-9]{5}-[a-fA-F0-9]{32}$"; + public static final String CONTEXT_KEY_REGEX = "^[a-zA-Z0-9_]+$"; + public static final String SDK_METRIC_NAME_VERSION = "sdk_name_version"; + public static final String SDK_METRIC_NAME_VERSION_PREFIX = "skyflow-java@"; + public static final String SDK_METRIC_CLIENT_DEVICE_MODEL = "sdk_client_device_model"; + public static final String SDK_METRIC_CLIENT_OS_DETAILS = "sdk_client_os_details"; + public static final String SDK_METRIC_RUNTIME_DETAILS = "sdk_runtime_details"; + public static final String SDK_METRIC_RUNTIME_DETAILS_PREFIX = "Java@"; + public static final String SDK_AUTH_HEADER_KEY = "x-skyflow-authorization"; + public static final String SDK_METRICS_HEADER_KEY = "sky-metadata"; + public static final String REQUEST_ID_HEADER_KEY = "x-request-id"; + public static final String ERROR_FROM_CLIENT_HEADER_KEY = "error-from-client"; + +} diff --git a/common/src/main/java/com/skyflow/utils/BaseUtils.java b/common/src/main/java/com/skyflow/utils/BaseUtils.java new file mode 100644 index 00000000..05db73f5 --- /dev/null +++ b/common/src/main/java/com/skyflow/utils/BaseUtils.java @@ -0,0 +1,177 @@ +package com.skyflow.utils; + +import com.google.gson.JsonObject; +import com.skyflow.config.BaseCredentials; +import com.skyflow.enums.Env; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; +import com.skyflow.logs.InfoLogs; +import com.skyflow.serviceaccount.util.BearerToken; +import com.skyflow.utils.logger.LogUtil; +import org.apache.commons.codec.binary.Base64; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Map; + +public class BaseUtils { + public static String generateBearerToken(BaseCredentials credentials) throws SkyflowException { + if (credentials.getPath() != null) { + BearerToken.BearerTokenBuilder builder = BearerToken.builder() + .setCredentials(new File(credentials.getPath())) + .setRoles(credentials.getRoles()); + Object ctx = credentials.getContext(); + if (ctx instanceof String) { + builder.setCtx((String) ctx); + } else if (ctx instanceof Map) { + builder.setCtx((Map) ctx); + } + return builder.build().getBearerToken(); + } else if (credentials.getCredentialsString() != null) { + BearerToken.BearerTokenBuilder builder = BearerToken.builder() + .setCredentials(credentials.getCredentialsString()) + .setRoles(credentials.getRoles()); + Object ctx = credentials.getContext(); + if (ctx instanceof String) { + builder.setCtx((String) ctx); + } else if (ctx instanceof Map) { + builder.setCtx((Map) ctx); + } + return builder.build().getBearerToken(); + } else { + return credentials.getToken(); + } + } + + public static String getVaultURL(String clusterId, Env env, String vaultDomain) { + StringBuilder sb = buildBaseUrl(clusterId, vaultDomain); + switch (env) { + case DEV: + sb.append(BaseConstants.DEV_DOMAIN); + break; + case STAGE: + sb.append(BaseConstants.STAGE_DOMAIN); + break; + case SANDBOX: + sb.append(BaseConstants.SANDBOX_DOMAIN); + break; + case PROD: + default: + sb.append(BaseConstants.PROD_DOMAIN); + break; + } + return sb.toString(); + } + + public static PrivateKey getPrivateKeyFromPem(String pemKey) throws SkyflowException { + String PKCS8PrivateHeader = BaseConstants.PKCS8_PRIVATE_HEADER; + String PKCS8PrivateFooter = BaseConstants.PKCS8_PRIVATE_FOOTER; + + String privateKeyContent = pemKey; + PrivateKey privateKey = null; + + if (pemKey.contains(PKCS8PrivateHeader)) { + privateKeyContent = privateKeyContent.replace(PKCS8PrivateHeader, ""); + privateKeyContent = privateKeyContent.replace(PKCS8PrivateFooter, ""); + privateKeyContent = privateKeyContent.replace("\n", ""); + privateKeyContent = privateKeyContent.replace("\r\n", ""); + privateKey = parsePkcs8PrivateKey(Base64.decodeBase64(privateKeyContent)); + } else { + LogUtil.printErrorLog(ErrorLogs.JWT_INVALID_FORMAT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.JwtInvalidFormat.getMessage()); + } + return privateKey; + } + + public static String getBaseURL(String url) throws MalformedURLException { + URL parsedUrl = new URL(url); + String protocol = parsedUrl.getProtocol(); + String host = parsedUrl.getHost(); + return String.format("%s://%s", protocol, host); + } + + public static String parameterizedString(String base, String... args) { + for (int index = 0; index < args.length; index++) { + base = base.replace("%s" + (index + 1), args[index]); + } + return base; + } + + protected static JsonObject getCommonMetrics() { + JsonObject details = new JsonObject(); + String deviceModel; + String osDetails; + String javaVersion; + // Retrieve device model + try { + deviceModel = System.getProperty("os.name"); + if (deviceModel == null) throw new Exception(); + } catch (Exception e) { + LogUtil.printInfoLog(parameterizedString( + InfoLogs.UNABLE_TO_GENERATE_SDK_METRIC.getLog(), + BaseConstants.SDK_METRIC_CLIENT_DEVICE_MODEL + )); + deviceModel = ""; + } + + // Retrieve OS details + try { + osDetails = System.getProperty("os.version"); + if (osDetails == null) throw new Exception(); + } catch (Exception e) { + LogUtil.printInfoLog(parameterizedString( + InfoLogs.UNABLE_TO_GENERATE_SDK_METRIC.getLog(), + BaseConstants.SDK_METRIC_CLIENT_OS_DETAILS + )); + osDetails = ""; + } + + // Retrieve Java version details + try { + javaVersion = System.getProperty("java.version"); + if (javaVersion == null) throw new Exception(); + } catch (Exception e) { + LogUtil.printInfoLog(parameterizedString( + InfoLogs.UNABLE_TO_GENERATE_SDK_METRIC.getLog(), + BaseConstants.SDK_METRIC_RUNTIME_DETAILS + )); + javaVersion = ""; + } + details.addProperty(BaseConstants.SDK_METRIC_CLIENT_DEVICE_MODEL, deviceModel); + details.addProperty(BaseConstants.SDK_METRIC_RUNTIME_DETAILS, BaseConstants.SDK_METRIC_RUNTIME_DETAILS_PREFIX + javaVersion); + details.addProperty(BaseConstants.SDK_METRIC_CLIENT_OS_DETAILS, osDetails); + return details; + } + + private static PrivateKey parsePkcs8PrivateKey(byte[] pkcs8Bytes) throws SkyflowException { + KeyFactory keyFactory; + PrivateKey privateKey = null; + try { + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Bytes); + keyFactory = KeyFactory.getInstance("RSA"); + privateKey = keyFactory.generatePrivate(keySpec); + } catch (NoSuchAlgorithmException e) { + LogUtil.printErrorLog(ErrorLogs.INVALID_ALGORITHM.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidAlgorithm.getMessage()); + } catch (InvalidKeySpecException e) { + LogUtil.printErrorLog(ErrorLogs.INVALID_KEY_SPEC.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidKeySpec.getMessage()); + } + return privateKey; + } + + private static StringBuilder buildBaseUrl(String clusterId, String vaultDomain) { + StringBuilder sb = new StringBuilder(BaseConstants.SECURE_PROTOCOL); + sb.append(clusterId); + sb.append(vaultDomain); + return sb; + } +} diff --git a/common/src/main/java/com/skyflow/utils/SdkVersion.java b/common/src/main/java/com/skyflow/utils/SdkVersion.java new file mode 100644 index 00000000..8136d8c9 --- /dev/null +++ b/common/src/main/java/com/skyflow/utils/SdkVersion.java @@ -0,0 +1,13 @@ +package com.skyflow.utils; + +public class SdkVersion { + private static String sdkPrefix = BaseConstants.SDK_PREFIX; + + public static String getSdkPrefix() { + return sdkPrefix; + } + + public static void setSdkPrefix(String sdkPrefix) { + SdkVersion.sdkPrefix = sdkPrefix; + } +} diff --git a/common/src/main/java/com/skyflow/utils/logger/LogUtil.java b/common/src/main/java/com/skyflow/utils/logger/LogUtil.java new file mode 100644 index 00000000..54fc7d47 --- /dev/null +++ b/common/src/main/java/com/skyflow/utils/logger/LogUtil.java @@ -0,0 +1,100 @@ +package com.skyflow.utils.logger; + +import com.skyflow.enums.LogLevel; +import com.skyflow.logs.InfoLogs; +import com.skyflow.utils.SdkVersion; + +import java.util.logging.*; + +public final class LogUtil { + private static final Logger LOGGER = Logger.getLogger(LogUtil.class.getName()); + private static final String SDK_LOG_PREFIX = "[" + SdkVersion.getSdkPrefix() + "] "; + private static boolean IS_LOGGER_SETUP_DONE = false; + + synchronized public static void setupLogger(LogLevel logLevel) { + IS_LOGGER_SETUP_DONE = true; + LogManager.getLogManager().reset(); + LOGGER.setUseParentHandlers(false); + Formatter formatter = new SimpleFormatter() { + private static final String format = "%s: %s %n"; + + // Override format method + @Override + public synchronized String format(LogRecord logRecord) { + return String.format( + format, + loggerLevelToLogLevelMap(logRecord.getLevel()), + logRecord.getMessage() + ); + } + }; + ConsoleHandler consoleHandler = new ConsoleHandler(); + consoleHandler.setFormatter(formatter); + consoleHandler.setLevel(Level.CONFIG); + + LOGGER.addHandler(consoleHandler); + LOGGER.setLevel(logLevelToLoggerLevelMap(logLevel)); + printInfoLog(InfoLogs.LOGGER_SETUP_DONE.getLog()); + } + + public static void printErrorLog(String message) { + if (IS_LOGGER_SETUP_DONE) + LOGGER.severe(SDK_LOG_PREFIX + message); + else { + setupLogger(LogLevel.ERROR); + LOGGER.severe(SDK_LOG_PREFIX + message); + } + } + + public static void printDebugLog(String message) { + if (IS_LOGGER_SETUP_DONE) + LOGGER.config(SDK_LOG_PREFIX + message); + } + + public static void printWarningLog(String message) { + if (IS_LOGGER_SETUP_DONE) + LOGGER.warning(SDK_LOG_PREFIX + message); + } + + public static void printInfoLog(String message) { + if (IS_LOGGER_SETUP_DONE) + LOGGER.info(SDK_LOG_PREFIX + message); + } + + + private static Level logLevelToLoggerLevelMap(LogLevel logLevel) { + Level loggerLevel; + switch (logLevel) { + case ERROR: + loggerLevel = Level.SEVERE; + break; + case WARN: + loggerLevel = Level.WARNING; + break; + case INFO: + loggerLevel = Level.INFO; + break; + case DEBUG: + loggerLevel = Level.CONFIG; + break; + default: + loggerLevel = Level.OFF; + } + return loggerLevel; + } + + private static LogLevel loggerLevelToLogLevelMap(Level loggerLevel) { + LogLevel logLevel; + if (Level.SEVERE.equals(loggerLevel)) { + logLevel = LogLevel.ERROR; + } else if (Level.WARNING.equals(loggerLevel)) { + logLevel = LogLevel.WARN; + } else if (Level.INFO.equals(loggerLevel)) { + logLevel = LogLevel.INFO; + } else if (Level.CONFIG.equals(loggerLevel)) { + logLevel = LogLevel.DEBUG; + } else + logLevel = LogLevel.OFF; + return logLevel; + } +} diff --git a/common/src/main/java/com/skyflow/utils/validations/BaseValidations.java b/common/src/main/java/com/skyflow/utils/validations/BaseValidations.java new file mode 100644 index 00000000..c2ee2df9 --- /dev/null +++ b/common/src/main/java/com/skyflow/utils/validations/BaseValidations.java @@ -0,0 +1,111 @@ +package com.skyflow.utils.validations; + +import com.skyflow.config.BaseCredentials; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; +import com.skyflow.utils.BaseConstants; +import com.skyflow.utils.BaseUtils; +import com.skyflow.utils.logger.LogUtil; + +import java.util.ArrayList; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class BaseValidations { + BaseValidations() { + } + + public static void validateCredentials(BaseCredentials credentials) throws SkyflowException { + int nonNullMembers = 0; + String path = credentials.getPath(); + String credentialsString = credentials.getCredentialsString(); + String token = credentials.getToken(); + String apiKey = credentials.getApiKey(); + Object context = credentials.getContext(); + ArrayList roles = credentials.getRoles(); + + if (path != null) nonNullMembers++; + if (credentialsString != null) nonNullMembers++; + if (token != null) nonNullMembers++; + if (apiKey != null) nonNullMembers++; + + if (nonNullMembers > 1) { + LogUtil.printErrorLog(ErrorLogs.MULTIPLE_TOKEN_GENERATION_MEANS_PASSED.getLog()); + throw new SkyflowException( + ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MultipleTokenGenerationMeansPassed.getMessage() + ); + } else if (nonNullMembers < 1) { + LogUtil.printErrorLog(ErrorLogs.NO_TOKEN_GENERATION_MEANS_PASSED.getLog()); + throw new SkyflowException( + ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NoTokenGenerationMeansPassed.getMessage() + ); + } else if (path != null && path.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_PATH.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialFilePath.getMessage()); + } else if (credentialsString != null && credentialsString.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_STRING.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialsString.getMessage()); + } else if (token != null && token.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_TOKEN_VALUE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyToken.getMessage()); + } else if (apiKey != null) { + if (apiKey.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_API_KEY_VALUE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyApikey.getMessage()); + } else { + Pattern pattern = Pattern.compile(BaseConstants.API_KEY_REGEX); + Matcher matcher = pattern.matcher(apiKey); + if (!matcher.matches()) { + LogUtil.printErrorLog(ErrorLogs.INVALID_API_KEY.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidApikey.getMessage()); + } + } + } else if (roles != null) { + if (roles.isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_ROLES.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoles.getMessage()); + } else { + for (int index = 0; index < roles.size(); index++) { + String role = roles.get(index); + if (role == null || role.trim().isEmpty()) { + LogUtil.printErrorLog(BaseUtils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_ROLE_IN_ROLES.getLog(), Integer.toString(index) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoleInRoles.getMessage()); + } + } + } + } + if (context != null) { + if (context instanceof String) { + String ctxStr = (String) context; + if (ctxStr.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); + } + } else if (context instanceof Map) { + Map ctxMap = (Map) context; + if (ctxMap.isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); + } + Pattern ctxKeyPattern = Pattern.compile(BaseConstants.CONTEXT_KEY_REGEX); + for (Object key : ctxMap.keySet()) { + if (key == null || !ctxKeyPattern.matcher(key.toString()).matches()) { + String keyStr = key == null ? "null" : key.toString(); + LogUtil.printErrorLog(BaseUtils.parameterizedString( + ErrorLogs.INVALID_CONTEXT_MAP_KEY.getLog(), keyStr)); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), + BaseUtils.parameterizedString(ErrorMessage.InvalidContextMapKey.getMessage(), keyStr)); + } + } + } else { + LogUtil.printErrorLog(ErrorLogs.INVALID_CONTEXT_TYPE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidContextType.getMessage()); + } + } + } +} diff --git a/common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java b/common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java new file mode 100644 index 00000000..d6cd31ae --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java @@ -0,0 +1,21 @@ +package com.skyflow.vault.controller; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; +import com.skyflow.utils.logger.LogUtil; + +import java.util.List; +import java.util.Map; + +public class BaseVaultController { + protected static final Gson GSON = new GsonBuilder().serializeNulls().create(); + + protected static SkyflowException wrapApiException(int statusCode, Throwable cause, + Map> headers, + Object responseBody, ErrorLogs errorLog) { + LogUtil.printErrorLog(errorLog.getLog()); + return new SkyflowException(statusCode, cause, headers, GSON.toJson(responseBody)); + } +} diff --git a/common/src/main/java/com/skyflow/vault/controller/IVaultController.java b/common/src/main/java/com/skyflow/vault/controller/IVaultController.java new file mode 100644 index 00000000..1c4f907f --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/controller/IVaultController.java @@ -0,0 +1,9 @@ +package com.skyflow.vault.controller; + +import com.skyflow.errors.SkyflowException; + +// Common interface — ONLY operations supported on both vault types. +public interface IVaultController { + InsertResp insert(InsertReq request) throws SkyflowException; + DetokenizeResp detokenize(DetokenizeReq request) throws SkyflowException; +} \ No newline at end of file diff --git a/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRequest.java new file mode 100644 index 00000000..d19d0432 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRequest.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class BaseDetokenizeRequest { +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java new file mode 100644 index 00000000..ad158145 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class BaseDetokenizeResponse { +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java new file mode 100644 index 00000000..9f463b6f --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class BaseInsertRequest { +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java new file mode 100644 index 00000000..7b5efb9b --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class BaseInsertResponse { +} diff --git a/flowvault/pom.xml b/flowvault/pom.xml new file mode 100644 index 00000000..9f36f6c4 --- /dev/null +++ b/flowvault/pom.xml @@ -0,0 +1,128 @@ + + + 4.0.0 + + com.skyflow + skyflow + 1.0.0 + ../pom.xml + + + skyflow-flowvault-java + 1.0.0 + jar + ${project.groupId}:${project.artifactId} + Skyflow V3 SDK for the Java programming language + https://github.com/skyflowapi/skyflow-java/tree/main + + + + The MIT License (MIT) + https://github.com/skyflowapi/skyflow-java/blob/main/LICENSE + + + + + skyflow + skyflow + + + + + 8 + 8 + UTF-8 + false + ${project.version} + + + + + + + com.skyflow + common + 1.0.1 + + + + + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + com.skyflow:common + + + + + + + + + + + + jfrog + + + central + prekarilabs.jfrog.io-releases + https://prekarilabs.jfrog.io/artifactory/skyflow-java + + + snapshots + prekarilabs.jfrog.io-snapshots + https://prekarilabs.jfrog.io/artifactory/skyflow-java + + + + + maven-central + + + central + https://central.sonatype.com/api/v1/publisher/upload + + + central-snapshots + https://central.sonatype.com/api/v1/publisher/upload + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.4.0 + true + + central + true + true + + + + + + + + diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java new file mode 100644 index 00000000..ff1eff08 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -0,0 +1,144 @@ +package com.skyflow; + +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; +import com.skyflow.logs.InfoLogs; +import com.skyflow.utils.Constants; +import com.skyflow.utils.SdkVersion; +import com.skyflow.utils.Utils; +import com.skyflow.utils.logger.LogUtil; +import com.skyflow.utils.validations.Validations; +import com.skyflow.vault.controller.VaultController; + +import java.util.LinkedHashMap; + +public final class Skyflow extends BaseSkyflow { + private final SkyflowClientBuilder builder; + + private Skyflow(SkyflowClientBuilder builder) { + super(builder); + this.builder = builder; + } + + public static SkyflowClientBuilder builder() { + SdkVersion.setSdkPrefix(Constants.SDK_PREFIX); + return new SkyflowClientBuilder(); + } + + public VaultConfig getVaultConfig() { + Object[] array = this.builder.vaultConfigMap.values().toArray(); + return (VaultConfig) array[0]; + } + + public VaultController vault() throws SkyflowException { + Object[] array = this.builder.vaultClientsMap.keySet().toArray(); + if (array.length < 1) { + LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + } + String vaultId = (String) array[0]; + VaultController controller = this.builder.vaultClientsMap.get(vaultId); + if (controller == null) { + LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + } + + return controller; + } + + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + private final LinkedHashMap vaultConfigMap; + private final LinkedHashMap vaultClientsMap; + protected Credentials skyflowCredentials; + public SkyflowClientBuilder() { + this.vaultConfigMap = new LinkedHashMap<>(); + this.vaultClientsMap = new LinkedHashMap<>(); + } + + public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); + Validations.validateVaultConfiguration(vaultConfig); + VaultConfig vaultConfigCopy; + try { + vaultConfigCopy = (VaultConfig) vaultConfig.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + if (!this.vaultClientsMap.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfigCopy.getVaultId() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), + ErrorMessage.VaultIdAlreadyInConfigList.getMessage()); + } else { + this.vaultConfigMap.put(vaultConfigCopy.getVaultId(), vaultConfigCopy); // add new config in map + this.vaultClientsMap.put(vaultConfigCopy.getVaultId(), new VaultController(vaultConfigCopy, this.skyflowCredentials)); // add new controller with new config + LogUtil.printInfoLog(Utils.parameterizedString( + InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfigCopy.getVaultId())); + } + return this; + } + + public SkyflowClientBuilder updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); + Validations.validateVaultConfiguration(vaultConfig); + if (this.vaultClientsMap.containsKey(vaultConfig.getVaultId())) { + VaultConfig existing = this.vaultConfigMap.get(vaultConfig.getVaultId()); + if (vaultConfig.getEnv() != null) existing.setEnv(vaultConfig.getEnv()); + if (vaultConfig.getClusterId() != null) existing.setClusterId(vaultConfig.getClusterId()); + if (vaultConfig.getCredentials() != null) existing.setCredentials(vaultConfig.getCredentials()); + this.vaultClientsMap.put(existing.getVaultId(), new VaultController(existing, this.skyflowCredentials)); + } else { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultConfig.getVaultId() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + } + return this; + } + + public SkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { + if (this.vaultClientsMap.containsKey(vaultId)) { + this.vaultClientsMap.remove(vaultId); + this.vaultConfigMap.remove(vaultId); + } else { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + } + return this; + } + + public SkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { + Validations.validateCredentials(credentials); + Credentials credentialsCopy; + try { + credentialsCopy = (Credentials) credentials.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + this.skyflowCredentials = credentialsCopy; + for (VaultController vault : this.vaultClientsMap.values()) { + vault.setCommonCredentials(this.skyflowCredentials); + } + return this; + } + + @Override + public SkyflowClientBuilder setLogLevel(LogLevel logLevel) { + super.setLogLevel(logLevel); + return this; + } + + public Skyflow build() { + return new Skyflow(this); + } + } + +} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/VaultClient.java b/flowvault/src/main/java/com/skyflow/VaultClient.java new file mode 100644 index 00000000..00a3d57d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/VaultClient.java @@ -0,0 +1,73 @@ +package com.skyflow; + +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.ApiClient; +import com.skyflow.generated.rest.ApiClientBuilder; +import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; +import com.skyflow.utils.Utils; + + +public class VaultClient extends BaseVaultClient { + private final VaultConfig vaultConfig; + private final ApiClientBuilder apiClientBuilder; + private ApiClient apiClient; + + protected VaultClient(VaultConfig vaultConfig, Credentials credentials) throws SkyflowException { + this.vaultConfig = vaultConfig; + this.commonCredentials = credentials; + this.apiClientBuilder = new ApiClientBuilder(); + this.apiClient = null; + updateVaultURL(); + } + + protected FlowserviceClient getRecordsApi() { + return this.apiClient.flowservice(); + } + + protected VaultConfig getVaultConfig() { + return vaultConfig; + } + + protected void setCommonCredentials(Credentials commonCredentials) throws SkyflowException { + this.commonCredentials = commonCredentials; + super.prioritiseCredentials(this.vaultConfig.getCredentials()); + } + + protected void setBearerToken() throws SkyflowException { + super.setBearerToken(this.vaultConfig.getCredentials()); + if (apiClient == null) { + updateExecutorInHTTP(); + this.apiClient = this.apiClientBuilder.build(); + } + } + + private void updateVaultURL() throws SkyflowException { + // Fetch vaultURL from ENV + String vaultURL = Utils.getEnvVaultURL(); + + // If vaultURL from ENV is null or empty, fetch vaultURL from vault config + if (vaultURL == null || vaultURL.isEmpty()) { + vaultURL = this.vaultConfig.getVaultURL(); + } + + // If vaultURL from vault config is also null or empty, construct vaultURL from clusterId passed in vault config + if (vaultURL == null || vaultURL.isEmpty()) { + vaultURL = Utils.getVaultURL(this.vaultConfig.getClusterId(), this.vaultConfig.getEnv()); + } + this.apiClientBuilder.url(vaultURL); + if (!vaultURL.equals(this.currentVaultURL)) { + this.currentVaultURL = vaultURL; + this.apiClient = null; + } + } + + protected void updateExecutorInHTTP() { + if (sharedHttpClient == null) { + sharedHttpClient = buildSharedHttpClient(() -> this.token); + apiClientBuilder.httpClient(sharedHttpClient); + } + } + +} diff --git a/flowvault/src/main/java/com/skyflow/config/Credentials.java b/flowvault/src/main/java/com/skyflow/config/Credentials.java new file mode 100644 index 00000000..1e13c146 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/config/Credentials.java @@ -0,0 +1,9 @@ +package com.skyflow.config; + +public class Credentials extends BaseCredentials { + public Credentials() { + super(); + } + + +} diff --git a/flowvault/src/main/java/com/skyflow/config/VaultConfig.java b/flowvault/src/main/java/com/skyflow/config/VaultConfig.java new file mode 100644 index 00000000..f90fa76c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/config/VaultConfig.java @@ -0,0 +1,33 @@ +package com.skyflow.config; + +import com.skyflow.enums.Env; + +public class VaultConfig extends BaseVaultConfig implements Cloneable { + + private Credentials credentials; + + public VaultConfig() { + super(); + this.credentials = null; + } + + public Credentials getCredentials() { + return credentials; + } + + public void setCredentials(Credentials credentials) { + this.credentials = credentials; + } + + + @Override + public Object clone() throws CloneNotSupportedException { + VaultConfig cloned = (VaultConfig) super.clone(); + if (this.credentials != null) { + cloned.credentials = (Credentials) this.credentials.clone(); + } + + return cloned; + } + +} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/enums/CustomHeaderKey.java b/flowvault/src/main/java/com/skyflow/enums/CustomHeaderKey.java new file mode 100644 index 00000000..8e6190c6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/enums/CustomHeaderKey.java @@ -0,0 +1,18 @@ +package com.skyflow.enums; + +public enum CustomHeaderKey { + SkyflowAccountID("x-skyflow-account-id"), + SkyflowAccountName("x-skyflow-account-name"), + RequestIDHeader("x-request-id"); + + private final String value; + + CustomHeaderKey(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } +} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/enums/UpsertType.java b/flowvault/src/main/java/com/skyflow/enums/UpsertType.java new file mode 100644 index 00000000..fa2350d2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/enums/UpsertType.java @@ -0,0 +1,18 @@ +package com.skyflow.enums; + +public enum UpsertType { + UPDATE("UPDATE"), + + REPLACE("REPLACE"); + + private final String value; + + UpsertType(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java new file mode 100644 index 00000000..02b972dd --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java @@ -0,0 +1,37 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.Suppliers; +import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; +import com.skyflow.generated.rest.resources.records.RecordsClient; + +import java.util.function.Supplier; + +public class ApiClient { + protected final ClientOptions clientOptions; + + protected final Supplier recordsClient; + + protected final Supplier flowserviceClient; + + public ApiClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.recordsClient = Suppliers.memoize(() -> new RecordsClient(clientOptions)); + this.flowserviceClient = Suppliers.memoize(() -> new FlowserviceClient(clientOptions)); + } + + public RecordsClient records() { + return this.recordsClient.get(); + } + + public FlowserviceClient flowservice() { + return this.flowserviceClient.get(); + } + + public static ApiClientBuilder builder() { + return new ApiClientBuilder(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java new file mode 100644 index 00000000..fa3d6e9d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java @@ -0,0 +1,48 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.Environment; +import okhttp3.OkHttpClient; + +public final class ApiClientBuilder { + private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); + + private Environment environment; + + public ApiClientBuilder url(String url) { + this.environment = Environment.custom(url); + return this; + } + + /** + * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. + */ + public ApiClientBuilder timeout(int timeout) { + this.clientOptionsBuilder.timeout(timeout); + return this; + } + + /** + * Sets the maximum number of retries for the client. Defaults to 2 retries. + */ + public ApiClientBuilder maxRetries(int maxRetries) { + this.clientOptionsBuilder.maxRetries(maxRetries); + return this; + } + + /** + * Sets the underlying OkHttp client + */ + public ApiClientBuilder httpClient(OkHttpClient httpClient) { + this.clientOptionsBuilder.httpClient(httpClient); + return this; + } + + public ApiClient build() { + clientOptionsBuilder.environment(this.environment); + return new ApiClient(clientOptionsBuilder.build()); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java new file mode 100644 index 00000000..840c0bad --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java @@ -0,0 +1,37 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.Suppliers; +import com.skyflow.generated.rest.resources.flowservice.AsyncFlowserviceClient; +import com.skyflow.generated.rest.resources.records.AsyncRecordsClient; + +import java.util.function.Supplier; + +public class AsyncApiClient { + protected final ClientOptions clientOptions; + + protected final Supplier recordsClient; + + protected final Supplier flowserviceClient; + + public AsyncApiClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.recordsClient = Suppliers.memoize(() -> new AsyncRecordsClient(clientOptions)); + this.flowserviceClient = Suppliers.memoize(() -> new AsyncFlowserviceClient(clientOptions)); + } + + public AsyncRecordsClient records() { + return this.recordsClient.get(); + } + + public AsyncFlowserviceClient flowservice() { + return this.flowserviceClient.get(); + } + + public static AsyncApiClientBuilder builder() { + return new AsyncApiClientBuilder(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java new file mode 100644 index 00000000..10c08d51 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java @@ -0,0 +1,48 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.Environment; +import okhttp3.OkHttpClient; + +public final class AsyncApiClientBuilder { + private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); + + private Environment environment; + + public AsyncApiClientBuilder url(String url) { + this.environment = Environment.custom(url); + return this; + } + + /** + * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. + */ + public AsyncApiClientBuilder timeout(int timeout) { + this.clientOptionsBuilder.timeout(timeout); + return this; + } + + /** + * Sets the maximum number of retries for the client. Defaults to 2 retries. + */ + public AsyncApiClientBuilder maxRetries(int maxRetries) { + this.clientOptionsBuilder.maxRetries(maxRetries); + return this; + } + + /** + * Sets the underlying OkHttp client + */ + public AsyncApiClientBuilder httpClient(OkHttpClient httpClient) { + this.clientOptionsBuilder.httpClient(httpClient); + return this; + } + + public AsyncApiClient build() { + clientOptionsBuilder.environment(this.environment); + return new AsyncApiClient(clientOptionsBuilder.build()); + } +} diff --git a/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java index 4fab1d41..be5247eb 100644 --- a/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java @@ -3,11 +3,12 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Response; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import okhttp3.Response; /** * This exception type will be thrown for any non-2XX API responses. diff --git a/src/main/java/com/skyflow/generated/rest/core/ApiClientException.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientException.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/ApiClientException.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientException.java diff --git a/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java index 9c81f1f5..c743352c 100644 --- a/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java @@ -3,11 +3,12 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Response; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import okhttp3.Response; public final class ApiClientHttpResponse { diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java new file mode 100644 index 00000000..2a5f0710 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java @@ -0,0 +1,171 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.OkHttpClient; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public final class ClientOptions { + private final Environment environment; + + private final Map headers; + + private final Map> headerSuppliers; + + private final OkHttpClient httpClient; + + private final int timeout; + + private ClientOptions( + Environment environment, + Map headers, + Map> headerSuppliers, + OkHttpClient httpClient, + int timeout) { + this.environment = environment; + this.headers = new HashMap<>(); + this.headers.putAll(headers); + this.headers.putAll(new HashMap() { + { + put("X-Fern-Language", "JAVA"); + put("X-Fern-SDK-Name", "com.skyflow.fern:api-sdk"); + put("X-Fern-SDK-Version", "0.0.98"); + } + }); + this.headerSuppliers = headerSuppliers; + this.httpClient = httpClient; + this.timeout = timeout; + } + + public Environment environment() { + return this.environment; + } + + public Map headers(RequestOptions requestOptions) { + Map values = new HashMap<>(this.headers); + headerSuppliers.forEach((key, supplier) -> { + values.put(key, supplier.get()); + }); + if (requestOptions != null) { + values.putAll(requestOptions.getHeaders()); + } + return values; + } + + public int timeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.timeout; + } + return requestOptions.getTimeout().orElse(this.timeout); + } + + public OkHttpClient httpClient() { + return this.httpClient; + } + + public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.httpClient; + } + return this.httpClient + .newBuilder() + .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit()) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private Environment environment; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + private int maxRetries = 2; + + private Optional timeout = Optional.empty(); + + private OkHttpClient httpClient = null; + + public Builder environment(Environment environment) { + this.environment = environment; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(int timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(Optional timeout) { + this.timeout = timeout; + return this; + } + + /** + * Override the maximum number of retries. Defaults to 2 retries. + */ + public Builder maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + public Builder httpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + public ClientOptions build() { + OkHttpClient.Builder httpClientBuilder = + this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder(); + + if (this.httpClient != null) { + timeout.ifPresent(timeout -> httpClientBuilder + .callTimeout(timeout, TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS)); + } else { + httpClientBuilder + .callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .addInterceptor(new RetryInterceptor(this.maxRetries)); + } + + this.httpClient = httpClientBuilder.build(); + this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000); + + return new ClientOptions(environment, headers, headerSuppliers, httpClient, this.timeout.get()); + } + } +} diff --git a/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java index 6be10979..a0a6d7c4 100644 --- a/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; + import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java new file mode 100644 index 00000000..2fc27c36 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java @@ -0,0 +1,20 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +public final class Environment { + private final String url; + + private Environment(String url) { + this.url = url; + } + + public String getUrl() { + return this.url; + } + + public static Environment custom(String url) { + return new Environment(url); + } +} diff --git a/src/main/java/com/skyflow/generated/rest/core/FileStream.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/FileStream.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/FileStream.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/FileStream.java index 6b459431..2131b0a4 100644 --- a/src/main/java/com/skyflow/generated/rest/core/FileStream.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/FileStream.java @@ -3,12 +3,13 @@ */ package com.skyflow.generated.rest.core; -import java.io.InputStream; -import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; import org.jetbrains.annotations.Nullable; +import java.io.InputStream; +import java.util.Objects; + /** * Represents a file stream with associated metadata for file uploads. */ diff --git a/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java index 545f6088..55c3c971 100644 --- a/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java @@ -3,9 +3,6 @@ */ package com.skyflow.generated.rest.core; -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.internal.Util; @@ -14,6 +11,10 @@ import okio.Source; import org.jetbrains.annotations.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; + /** * A custom implementation of OkHttp's RequestBody that wraps an InputStream. * This class allows streaming of data from an InputStream directly to an HTTP request body, diff --git a/src/main/java/com/skyflow/generated/rest/core/MediaTypes.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/MediaTypes.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/MediaTypes.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/MediaTypes.java diff --git a/src/main/java/com/skyflow/generated/rest/core/Nullable.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Nullable.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/Nullable.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/Nullable.java diff --git a/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java diff --git a/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java index 3b7894e0..acec32b4 100644 --- a/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + import java.io.IOException; public final class ObjectMappers { diff --git a/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java index e9e18fb9..c0687736 100644 --- a/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java @@ -7,14 +7,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; import okhttp3.HttpUrl; import okhttp3.MultipartBody; +import java.util.*; + public class QueryStringMapper { private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER; diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java new file mode 100644 index 00000000..b8a8d14b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java @@ -0,0 +1,87 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public final class RequestOptions { + private final Optional timeout; + + private final TimeUnit timeoutTimeUnit; + + private final Map headers; + + private final Map> headerSuppliers; + + private RequestOptions( + Optional timeout, + TimeUnit timeoutTimeUnit, + Map headers, + Map> headerSuppliers) { + this.timeout = timeout; + this.timeoutTimeUnit = timeoutTimeUnit; + this.headers = headers; + this.headerSuppliers = headerSuppliers; + } + + public Optional getTimeout() { + return timeout; + } + + public TimeUnit getTimeoutTimeUnit() { + return timeoutTimeUnit; + } + + public Map getHeaders() { + Map headers = new HashMap<>(); + headers.putAll(this.headers); + this.headerSuppliers.forEach((key, supplier) -> { + headers.put(key, supplier.get()); + }); + return headers; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private Optional timeout = Optional.empty(); + + private TimeUnit timeoutTimeUnit = TimeUnit.SECONDS; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + public Builder timeout(Integer timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + public Builder timeout(Integer timeout, TimeUnit timeoutTimeUnit) { + this.timeout = Optional.of(timeout); + this.timeoutTimeUnit = timeoutTimeUnit; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + public RequestOptions build() { + return new RequestOptions(timeout, timeoutTimeUnit, headers, headerSuppliers); + } + } +} diff --git a/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java index d8df7715..1bb0b5dc 100644 --- a/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java @@ -3,9 +3,10 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Response; + import java.io.FilterInputStream; import java.io.IOException; -import okhttp3.Response; /** * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the diff --git a/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java index ed894407..e6c1a525 100644 --- a/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java @@ -3,9 +3,10 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Response; + import java.io.FilterReader; import java.io.IOException; -import okhttp3.Response; /** * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the diff --git a/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java index eda7d265..7a28c3c9 100644 --- a/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java @@ -3,12 +3,13 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Interceptor; +import okhttp3.Response; + import java.io.IOException; import java.time.Duration; import java.util.Optional; import java.util.Random; -import okhttp3.Interceptor; -import okhttp3.Response; public class RetryInterceptor implements Interceptor { diff --git a/src/main/java/com/skyflow/generated/rest/core/Stream.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Stream.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/Stream.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/Stream.java diff --git a/src/main/java/com/skyflow/generated/rest/core/Suppliers.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Suppliers.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/Suppliers.java rename to flowvault/src/main/java/com/skyflow/generated/rest/core/Suppliers.java diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncFlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncFlowserviceClient.java new file mode 100644 index 00000000..1fd59fe9 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncFlowserviceClient.java @@ -0,0 +1,129 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.flowservice.requests.*; +import com.skyflow.generated.rest.types.*; + +import java.util.concurrent.CompletableFuture; + +public class AsyncFlowserviceClient { + protected final ClientOptions clientOptions; + + private final AsyncRawFlowserviceClient rawClient; + + public AsyncFlowserviceClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new AsyncRawFlowserviceClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public AsyncRawFlowserviceClient withRawResponse() { + return this.rawClient; + } + + public CompletableFuture delete() { + return this.rawClient.delete().thenApply(response -> response.body()); + } + + public CompletableFuture delete(V1DeleteRequest request) { + return this.rawClient.delete(request).thenApply(response -> response.body()); + } + + public CompletableFuture delete(V1DeleteRequest request, RequestOptions requestOptions) { + return this.rawClient.delete(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture get() { + return this.rawClient.get().thenApply(response -> response.body()); + } + + public CompletableFuture get(V1GetRequest request) { + return this.rawClient.get(request).thenApply(response -> response.body()); + } + + public CompletableFuture get(V1GetRequest request, RequestOptions requestOptions) { + return this.rawClient.get(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture insert() { + return this.rawClient.insert().thenApply(response -> response.body()); + } + + public CompletableFuture insert(V1InsertRequest request) { + return this.rawClient.insert(request).thenApply(response -> response.body()); + } + + public CompletableFuture insert(V1InsertRequest request, RequestOptions requestOptions) { + return this.rawClient.insert(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture update() { + return this.rawClient.update().thenApply(response -> response.body()); + } + + public CompletableFuture update(V1UpdateRequest request) { + return this.rawClient.update(request).thenApply(response -> response.body()); + } + + public CompletableFuture update(V1UpdateRequest request, RequestOptions requestOptions) { + return this.rawClient.update(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture deletetoken() { + return this.rawClient.deletetoken().thenApply(response -> response.body()); + } + + public CompletableFuture deletetoken(V1FlowDeleteTokenRequest request) { + return this.rawClient.deletetoken(request).thenApply(response -> response.body()); + } + + public CompletableFuture deletetoken( + V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { + return this.rawClient.deletetoken(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture detokenize() { + return this.rawClient.detokenize().thenApply(response -> response.body()); + } + + public CompletableFuture detokenize(V1FlowDetokenizeRequest request) { + return this.rawClient.detokenize(request).thenApply(response -> response.body()); + } + + public CompletableFuture detokenize( + V1FlowDetokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.detokenize(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture tokenize() { + return this.rawClient.tokenize().thenApply(response -> response.body()); + } + + public CompletableFuture tokenize(V1FlowTokenizeRequest request) { + return this.rawClient.tokenize(request).thenApply(response -> response.body()); + } + + public CompletableFuture tokenize( + V1FlowTokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.tokenize(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture flowvaultmetrics() { + return this.rawClient.flowvaultmetrics().thenApply(response -> response.body()); + } + + public CompletableFuture flowvaultmetrics(V1FlowVaultMetricsRequest request) { + return this.rawClient.flowvaultmetrics(request).thenApply(response -> response.body()); + } + + public CompletableFuture flowvaultmetrics( + V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { + return this.rawClient.flowvaultmetrics(request, requestOptions).thenApply(response -> response.body()); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncRawFlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncRawFlowserviceClient.java new file mode 100644 index 00000000..17f85d0c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncRawFlowserviceClient.java @@ -0,0 +1,533 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.resources.flowservice.requests.*; +import com.skyflow.generated.rest.types.*; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +public class AsyncRawFlowserviceClient { + protected final ClientOptions clientOptions; + + public AsyncRawFlowserviceClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + public CompletableFuture> delete() { + return delete(V1DeleteRequest.builder().build()); + } + + public CompletableFuture> delete(V1DeleteRequest request) { + return delete(request, null); + } + + public CompletableFuture> delete( + V1DeleteRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/delete") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1DeleteResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> get() { + return get(V1GetRequest.builder().build()); + } + + public CompletableFuture> get(V1GetRequest request) { + return get(request, null); + } + + public CompletableFuture> get( + V1GetRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/get") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1GetResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> insert() { + return insert(V1InsertRequest.builder().build()); + } + + public CompletableFuture> insert(V1InsertRequest request) { + return insert(request, null); + } + + public CompletableFuture> insert( + V1InsertRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/insert") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1InsertResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> update() { + return update(V1UpdateRequest.builder().build()); + } + + public CompletableFuture> update(V1UpdateRequest request) { + return update(request, null); + } + + public CompletableFuture> update( + V1UpdateRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/update") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1UpdateResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> deletetoken() { + return deletetoken(V1FlowDeleteTokenRequest.builder().build()); + } + + public CompletableFuture> deletetoken( + V1FlowDeleteTokenRequest request) { + return deletetoken(request, null); + } + + public CompletableFuture> deletetoken( + V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/delete") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue( + responseBody.string(), V1FlowDeleteTokenResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> detokenize() { + return detokenize(V1FlowDetokenizeRequest.builder().build()); + } + + public CompletableFuture> detokenize( + V1FlowDetokenizeRequest request) { + return detokenize(request, null); + } + + public CompletableFuture> detokenize( + V1FlowDetokenizeRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/detokenize") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue( + responseBody.string(), V1FlowDetokenizeResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> tokenize() { + return tokenize(V1FlowTokenizeRequest.builder().build()); + } + + public CompletableFuture> tokenize(V1FlowTokenizeRequest request) { + return tokenize(request, null); + } + + public CompletableFuture> tokenize( + V1FlowTokenizeRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/tokenize") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue( + responseBody.string(), V1FlowTokenizeResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> flowvaultmetrics() { + return flowvaultmetrics(V1FlowVaultMetricsRequest.builder().build()); + } + + public CompletableFuture> flowvaultmetrics( + V1FlowVaultMetricsRequest request) { + return flowvaultmetrics(request, null); + } + + public CompletableFuture> flowvaultmetrics( + V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/vaults/metrics") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue( + responseBody.string(), V1FlowVaultMetricsResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/FlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/FlowserviceClient.java new file mode 100644 index 00000000..8da9c9a5 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/FlowserviceClient.java @@ -0,0 +1,124 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.flowservice.requests.*; +import com.skyflow.generated.rest.types.*; + +public class FlowserviceClient { + protected final ClientOptions clientOptions; + + private final RawFlowserviceClient rawClient; + + public FlowserviceClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new RawFlowserviceClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public RawFlowserviceClient withRawResponse() { + return this.rawClient; + } + + public V1DeleteResponse delete() { + return this.rawClient.delete().body(); + } + + public V1DeleteResponse delete(V1DeleteRequest request) { + return this.rawClient.delete(request).body(); + } + + public V1DeleteResponse delete(V1DeleteRequest request, RequestOptions requestOptions) { + return this.rawClient.delete(request, requestOptions).body(); + } + + public V1GetResponse get() { + return this.rawClient.get().body(); + } + + public V1GetResponse get(V1GetRequest request) { + return this.rawClient.get(request).body(); + } + + public V1GetResponse get(V1GetRequest request, RequestOptions requestOptions) { + return this.rawClient.get(request, requestOptions).body(); + } + + public V1InsertResponse insert() { + return this.rawClient.insert().body(); + } + + public V1InsertResponse insert(V1InsertRequest request) { + return this.rawClient.insert(request).body(); + } + + public V1InsertResponse insert(V1InsertRequest request, RequestOptions requestOptions) { + return this.rawClient.insert(request, requestOptions).body(); + } + + public V1UpdateResponse update() { + return this.rawClient.update().body(); + } + + public V1UpdateResponse update(V1UpdateRequest request) { + return this.rawClient.update(request).body(); + } + + public V1UpdateResponse update(V1UpdateRequest request, RequestOptions requestOptions) { + return this.rawClient.update(request, requestOptions).body(); + } + + public V1FlowDeleteTokenResponse deletetoken() { + return this.rawClient.deletetoken().body(); + } + + public V1FlowDeleteTokenResponse deletetoken(V1FlowDeleteTokenRequest request) { + return this.rawClient.deletetoken(request).body(); + } + + public V1FlowDeleteTokenResponse deletetoken(V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { + return this.rawClient.deletetoken(request, requestOptions).body(); + } + + public V1FlowDetokenizeResponse detokenize() { + return this.rawClient.detokenize().body(); + } + + public V1FlowDetokenizeResponse detokenize(V1FlowDetokenizeRequest request) { + return this.rawClient.detokenize(request).body(); + } + + public V1FlowDetokenizeResponse detokenize(V1FlowDetokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.detokenize(request, requestOptions).body(); + } + + public V1FlowTokenizeResponse tokenize() { + return this.rawClient.tokenize().body(); + } + + public V1FlowTokenizeResponse tokenize(V1FlowTokenizeRequest request) { + return this.rawClient.tokenize(request).body(); + } + + public V1FlowTokenizeResponse tokenize(V1FlowTokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.tokenize(request, requestOptions).body(); + } + + public V1FlowVaultMetricsResponse flowvaultmetrics() { + return this.rawClient.flowvaultmetrics().body(); + } + + public V1FlowVaultMetricsResponse flowvaultmetrics(V1FlowVaultMetricsRequest request) { + return this.rawClient.flowvaultmetrics(request).body(); + } + + public V1FlowVaultMetricsResponse flowvaultmetrics( + V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { + return this.rawClient.flowvaultmetrics(request, requestOptions).body(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/RawFlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/RawFlowserviceClient.java new file mode 100644 index 00000000..f1203085 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/RawFlowserviceClient.java @@ -0,0 +1,412 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.resources.flowservice.requests.*; +import com.skyflow.generated.rest.types.*; +import okhttp3.*; + +import java.io.IOException; + +public class RawFlowserviceClient { + protected final ClientOptions clientOptions; + + public RawFlowserviceClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + public ApiClientHttpResponse delete() { + return delete(V1DeleteRequest.builder().build()); + } + + public ApiClientHttpResponse delete(V1DeleteRequest request) { + return delete(request, null); + } + + public ApiClientHttpResponse delete(V1DeleteRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/delete") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1DeleteResponse.class), response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + public ApiClientHttpResponse get() { + return get(V1GetRequest.builder().build()); + } + + public ApiClientHttpResponse get(V1GetRequest request) { + return get(request, null); + } + + public ApiClientHttpResponse get(V1GetRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/get") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1GetResponse.class), response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + public ApiClientHttpResponse insert() { + return insert(V1InsertRequest.builder().build()); + } + + public ApiClientHttpResponse insert(V1InsertRequest request) { + return insert(request, null); + } + + public ApiClientHttpResponse insert(V1InsertRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/insert") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1InsertResponse.class), response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + public ApiClientHttpResponse update() { + return update(V1UpdateRequest.builder().build()); + } + + public ApiClientHttpResponse update(V1UpdateRequest request) { + return update(request, null); + } + + public ApiClientHttpResponse update(V1UpdateRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/update") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1UpdateResponse.class), response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + public ApiClientHttpResponse deletetoken() { + return deletetoken(V1FlowDeleteTokenRequest.builder().build()); + } + + public ApiClientHttpResponse deletetoken(V1FlowDeleteTokenRequest request) { + return deletetoken(request, null); + } + + public ApiClientHttpResponse deletetoken( + V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/delete") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowDeleteTokenResponse.class), + response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + public ApiClientHttpResponse detokenize() { + return detokenize(V1FlowDetokenizeRequest.builder().build()); + } + + public ApiClientHttpResponse detokenize(V1FlowDetokenizeRequest request) { + return detokenize(request, null); + } + + public ApiClientHttpResponse detokenize( + V1FlowDetokenizeRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/detokenize") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowDetokenizeResponse.class), + response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + public ApiClientHttpResponse tokenize() { + return tokenize(V1FlowTokenizeRequest.builder().build()); + } + + public ApiClientHttpResponse tokenize(V1FlowTokenizeRequest request) { + return tokenize(request, null); + } + + public ApiClientHttpResponse tokenize( + V1FlowTokenizeRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/tokenize") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowTokenizeResponse.class), + response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + public ApiClientHttpResponse flowvaultmetrics() { + return flowvaultmetrics(V1FlowVaultMetricsRequest.builder().build()); + } + + public ApiClientHttpResponse flowvaultmetrics(V1FlowVaultMetricsRequest request) { + return flowvaultmetrics(request, null); + } + + public ApiClientHttpResponse flowvaultmetrics( + V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/vaults/metrics") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowVaultMetricsResponse.class), + response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1DeleteRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1DeleteRequest.java new file mode 100644 index 00000000..27e22a8d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1DeleteRequest.java @@ -0,0 +1,186 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.V1UniqueValue; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1DeleteRequest.Builder.class) +public final class V1DeleteRequest { + private final Optional vaultId; + + private final Optional tableName; + + private final Optional> skyflowIDs; + + private final Optional> uniqueValues; + + private final Map additionalProperties; + + private V1DeleteRequest( + Optional vaultId, + Optional tableName, + Optional> skyflowIDs, + Optional> uniqueValues, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.skyflowIDs = skyflowIDs; + this.uniqueValues = uniqueValues; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault where data is being deleted + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Name of the table where data is being deleted + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return Skyflow ID for the record to be deleted + */ + @JsonProperty("skyflowIDs") + public Optional> getSkyflowIDs() { + return skyflowIDs; + } + + /** + * @return List of unique constraint values to query records by data + */ + @JsonProperty("uniqueValues") + public Optional> getUniqueValues() { + return uniqueValues; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1DeleteRequest && equalTo((V1DeleteRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1DeleteRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && skyflowIDs.equals(other.skyflowIDs) + && uniqueValues.equals(other.uniqueValues); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tableName, this.skyflowIDs, this.uniqueValues); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional tableName = Optional.empty(); + + private Optional> skyflowIDs = Optional.empty(); + + private Optional> uniqueValues = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1DeleteRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + skyflowIDs(other.getSkyflowIDs()); + uniqueValues(other.getUniqueValues()); + return this; + } + + /** + *

ID of the vault where data is being deleted

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Name of the table where data is being deleted

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

Skyflow ID for the record to be deleted

+ */ + @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) + public Builder skyflowIDs(Optional> skyflowIDs) { + this.skyflowIDs = skyflowIDs; + return this; + } + + public Builder skyflowIDs(List skyflowIDs) { + this.skyflowIDs = Optional.ofNullable(skyflowIDs); + return this; + } + + /** + *

List of unique constraint values to query records by data

+ */ + @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) + public Builder uniqueValues(Optional> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + public Builder uniqueValues(List uniqueValues) { + this.uniqueValues = Optional.ofNullable(uniqueValues); + return this; + } + + public V1DeleteRequest build() { + return new V1DeleteRequest(vaultId, tableName, skyflowIDs, uniqueValues, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDeleteTokenRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDeleteTokenRequest.java new file mode 100644 index 00000000..6bc8a4e6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDeleteTokenRequest.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowDeleteTokenRequest.Builder.class) +public final class V1FlowDeleteTokenRequest { + private final Optional vaultId; + + private final Optional> tokens; + + private final Map additionalProperties; + + private V1FlowDeleteTokenRequest( + Optional vaultId, Optional> tokens, Map additionalProperties) { + this.vaultId = vaultId; + this.tokens = tokens; + this.additionalProperties = additionalProperties; + } + + /** + * @return Vault ID + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Token value + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowDeleteTokenRequest && equalTo((V1FlowDeleteTokenRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowDeleteTokenRequest other) { + return vaultId.equals(other.vaultId) && tokens.equals(other.tokens); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tokens); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional> tokens = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowDeleteTokenRequest other) { + vaultId(other.getVaultId()); + tokens(other.getTokens()); + return this; + } + + /** + *

Vault ID

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Token value

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + public Builder tokens(List tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + public V1FlowDeleteTokenRequest build() { + return new V1FlowDeleteTokenRequest(vaultId, tokens, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDetokenizeRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDetokenizeRequest.java new file mode 100644 index 00000000..bdbe3bf2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDetokenizeRequest.java @@ -0,0 +1,156 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.V1TokenGroupRedactions; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowDetokenizeRequest.Builder.class) +public final class V1FlowDetokenizeRequest { + private final Optional vaultId; + + private final Optional> tokens; + + private final Optional> tokenGroupRedactions; + + private final Map additionalProperties; + + private V1FlowDetokenizeRequest( + Optional vaultId, + Optional> tokens, + Optional> tokenGroupRedactions, + Map additionalProperties) { + this.vaultId = vaultId; + this.tokens = tokens; + this.tokenGroupRedactions = tokenGroupRedactions; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault where detokenizing + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Token to be detokenized + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + /** + * @return List of token groups to be redacted. + */ + @JsonProperty("tokenGroupRedactions") + public Optional> getTokenGroupRedactions() { + return tokenGroupRedactions; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowDetokenizeRequest && equalTo((V1FlowDetokenizeRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowDetokenizeRequest other) { + return vaultId.equals(other.vaultId) + && tokens.equals(other.tokens) + && tokenGroupRedactions.equals(other.tokenGroupRedactions); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tokens, this.tokenGroupRedactions); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional> tokens = Optional.empty(); + + private Optional> tokenGroupRedactions = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowDetokenizeRequest other) { + vaultId(other.getVaultId()); + tokens(other.getTokens()); + tokenGroupRedactions(other.getTokenGroupRedactions()); + return this; + } + + /** + *

ID of the vault where detokenizing

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Token to be detokenized

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + public Builder tokens(List tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + /** + *

List of token groups to be redacted.

+ */ + @JsonSetter(value = "tokenGroupRedactions", nulls = Nulls.SKIP) + public Builder tokenGroupRedactions(Optional> tokenGroupRedactions) { + this.tokenGroupRedactions = tokenGroupRedactions; + return this; + } + + public Builder tokenGroupRedactions(List tokenGroupRedactions) { + this.tokenGroupRedactions = Optional.ofNullable(tokenGroupRedactions); + return this; + } + + public V1FlowDetokenizeRequest build() { + return new V1FlowDetokenizeRequest(vaultId, tokens, tokenGroupRedactions, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowTokenizeRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowTokenizeRequest.java new file mode 100644 index 00000000..a27d7b62 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowTokenizeRequest.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowTokenizeRequest.Builder.class) +public final class V1FlowTokenizeRequest { + private final Optional vaultId; + + private final Optional> data; + + private final Map additionalProperties; + + private V1FlowTokenizeRequest( + Optional vaultId, + Optional> data, + Map additionalProperties) { + this.vaultId = vaultId; + this.data = data; + this.additionalProperties = additionalProperties; + } + + /** + * @return Vault ID. + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Data to be tokenized + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowTokenizeRequest && equalTo((V1FlowTokenizeRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowTokenizeRequest other) { + return vaultId.equals(other.vaultId) && data.equals(other.data); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId, this.data); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional> data = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowTokenizeRequest other) { + vaultId(other.getVaultId()); + data(other.getData()); + return this; + } + + /** + *

Vault ID.

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Data to be tokenized

+ */ + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Optional> data) { + this.data = data; + return this; + } + + public Builder data(List data) { + this.data = Optional.ofNullable(data); + return this; + } + + public V1FlowTokenizeRequest build() { + return new V1FlowTokenizeRequest(vaultId, data, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowVaultMetricsRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowVaultMetricsRequest.java new file mode 100644 index 00000000..026d2d30 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowVaultMetricsRequest.java @@ -0,0 +1,96 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowVaultMetricsRequest.Builder.class) +public final class V1FlowVaultMetricsRequest { + private final Optional vaultId; + + private final Map additionalProperties; + + private V1FlowVaultMetricsRequest(Optional vaultId, Map additionalProperties) { + this.vaultId = vaultId; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault to get metrics for + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowVaultMetricsRequest && equalTo((V1FlowVaultMetricsRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowVaultMetricsRequest other) { + return vaultId.equals(other.vaultId); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowVaultMetricsRequest other) { + vaultId(other.getVaultId()); + return this; + } + + /** + *

ID of the vault to get metrics for

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + public V1FlowVaultMetricsRequest build() { + return new V1FlowVaultMetricsRequest(vaultId, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1GetRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1GetRequest.java new file mode 100644 index 00000000..415f5291 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1GetRequest.java @@ -0,0 +1,357 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.V1ColumnRedactions; +import com.skyflow.generated.rest.types.V1GetRequestData; +import com.skyflow.generated.rest.types.V1UniqueValue; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1GetRequest.Builder.class) +public final class V1GetRequest { + private final Optional vaultId; + + private final Optional tableName; + + private final Optional> skyflowIDs; + + private final Optional> columnRedactions; + + private final Optional> columns; + + private final Optional limit; + + private final Optional offset; + + private final Optional> uniqueValues; + + private final Optional> records; + + private final Map additionalProperties; + + private V1GetRequest( + Optional vaultId, + Optional tableName, + Optional> skyflowIDs, + Optional> columnRedactions, + Optional> columns, + Optional limit, + Optional offset, + Optional> uniqueValues, + Optional> records, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.skyflowIDs = skyflowIDs; + this.columnRedactions = columnRedactions; + this.columns = columns; + this.limit = limit; + this.offset = offset; + this.uniqueValues = uniqueValues; + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault where data is being fetched + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Name of the table where data is being fetched + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return Skyflow ID for the record to be fetched + */ + @JsonProperty("skyflowIDs") + public Optional> getSkyflowIDs() { + return skyflowIDs; + } + + /** + * @return List of columns to be redacted. + */ + @JsonProperty("columnRedactions") + public Optional> getColumnRedactions() { + return columnRedactions; + } + + /** + * @return List of columns to be fetched. + */ + @JsonProperty("columns") + public Optional> getColumns() { + return columns; + } + + /** + * @return Limit for the number of records to be fetched + */ + @JsonProperty("limit") + public Optional getLimit() { + return limit; + } + + /** + * @return Offset for the number of records to be fetched + */ + @JsonProperty("offset") + public Optional getOffset() { + return offset; + } + + /** + * @return List of unique constraint values to query records by data + */ + @JsonProperty("uniqueValues") + public Optional> getUniqueValues() { + return uniqueValues; + } + + /** + * @return List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table. + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1GetRequest && equalTo((V1GetRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1GetRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && skyflowIDs.equals(other.skyflowIDs) + && columnRedactions.equals(other.columnRedactions) + && columns.equals(other.columns) + && limit.equals(other.limit) + && offset.equals(other.offset) + && uniqueValues.equals(other.uniqueValues) + && records.equals(other.records); + } + + @Override + public int hashCode() { + return Objects.hash( + this.vaultId, + this.tableName, + this.skyflowIDs, + this.columnRedactions, + this.columns, + this.limit, + this.offset, + this.uniqueValues, + this.records); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional tableName = Optional.empty(); + + private Optional> skyflowIDs = Optional.empty(); + + private Optional> columnRedactions = Optional.empty(); + + private Optional> columns = Optional.empty(); + + private Optional limit = Optional.empty(); + + private Optional offset = Optional.empty(); + + private Optional> uniqueValues = Optional.empty(); + + private Optional> records = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1GetRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + skyflowIDs(other.getSkyflowIDs()); + columnRedactions(other.getColumnRedactions()); + columns(other.getColumns()); + limit(other.getLimit()); + offset(other.getOffset()); + uniqueValues(other.getUniqueValues()); + records(other.getRecords()); + return this; + } + + /** + *

ID of the vault where data is being fetched

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Name of the table where data is being fetched

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

Skyflow ID for the record to be fetched

+ */ + @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) + public Builder skyflowIDs(Optional> skyflowIDs) { + this.skyflowIDs = skyflowIDs; + return this; + } + + public Builder skyflowIDs(List skyflowIDs) { + this.skyflowIDs = Optional.ofNullable(skyflowIDs); + return this; + } + + /** + *

List of columns to be redacted.

+ */ + @JsonSetter(value = "columnRedactions", nulls = Nulls.SKIP) + public Builder columnRedactions(Optional> columnRedactions) { + this.columnRedactions = columnRedactions; + return this; + } + + public Builder columnRedactions(List columnRedactions) { + this.columnRedactions = Optional.ofNullable(columnRedactions); + return this; + } + + /** + *

List of columns to be fetched.

+ */ + @JsonSetter(value = "columns", nulls = Nulls.SKIP) + public Builder columns(Optional> columns) { + this.columns = columns; + return this; + } + + public Builder columns(List columns) { + this.columns = Optional.ofNullable(columns); + return this; + } + + /** + *

Limit for the number of records to be fetched

+ */ + @JsonSetter(value = "limit", nulls = Nulls.SKIP) + public Builder limit(Optional limit) { + this.limit = limit; + return this; + } + + public Builder limit(Integer limit) { + this.limit = Optional.ofNullable(limit); + return this; + } + + /** + *

Offset for the number of records to be fetched

+ */ + @JsonSetter(value = "offset", nulls = Nulls.SKIP) + public Builder offset(Optional offset) { + this.offset = offset; + return this; + } + + public Builder offset(Integer offset) { + this.offset = Optional.ofNullable(offset); + return this; + } + + /** + *

List of unique constraint values to query records by data

+ */ + @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) + public Builder uniqueValues(Optional> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + public Builder uniqueValues(List uniqueValues) { + this.uniqueValues = Optional.ofNullable(uniqueValues); + return this; + } + + /** + *

List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + public V1GetRequest build() { + return new V1GetRequest( + vaultId, + tableName, + skyflowIDs, + columnRedactions, + columns, + limit, + offset, + uniqueValues, + records, + additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1InsertRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1InsertRequest.java new file mode 100644 index 00000000..47a58cb2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1InsertRequest.java @@ -0,0 +1,181 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.V1InsertRecordData; +import com.skyflow.generated.rest.types.V1Upsert; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1InsertRequest.Builder.class) +public final class V1InsertRequest { + private final Optional vaultId; + + private final Optional tableName; + + private final Optional> records; + + private final Optional upsert; + + private final Map additionalProperties; + + private V1InsertRequest( + Optional vaultId, + Optional tableName, + Optional> records, + Optional upsert, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.records = records; + this.upsert = upsert; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault where data is being inserted + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Name of the table where data is being inserted + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return List of data row wise that is to be inserted in the vault + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @JsonProperty("upsert") + public Optional getUpsert() { + return upsert; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1InsertRequest && equalTo((V1InsertRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1InsertRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && records.equals(other.records) + && upsert.equals(other.upsert); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tableName, this.records, this.upsert); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional tableName = Optional.empty(); + + private Optional> records = Optional.empty(); + + private Optional upsert = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1InsertRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + records(other.getRecords()); + upsert(other.getUpsert()); + return this; + } + + /** + *

ID of the vault where data is being inserted

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Name of the table where data is being inserted

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

List of data row wise that is to be inserted in the vault

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + @JsonSetter(value = "upsert", nulls = Nulls.SKIP) + public Builder upsert(Optional upsert) { + this.upsert = upsert; + return this; + } + + public Builder upsert(V1Upsert upsert) { + this.upsert = Optional.ofNullable(upsert); + return this; + } + + public V1InsertRequest build() { + return new V1InsertRequest(vaultId, tableName, records, upsert, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1UpdateRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1UpdateRequest.java new file mode 100644 index 00000000..6f8b303e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1UpdateRequest.java @@ -0,0 +1,181 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.flowservice.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.FlowEnumUpdateType; +import com.skyflow.generated.rest.types.V1UpdateRecordData; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1UpdateRequest.Builder.class) +public final class V1UpdateRequest { + private final Optional vaultId; + + private final Optional tableName; + + private final Optional> records; + + private final Optional updateType; + + private final Map additionalProperties; + + private V1UpdateRequest( + Optional vaultId, + Optional tableName, + Optional> records, + Optional updateType, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.records = records; + this.updateType = updateType; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault where data is being updated + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Name of the table where data is being updated + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return List of data row wise that is to be updated in the vault + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @JsonProperty("updateType") + public Optional getUpdateType() { + return updateType; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1UpdateRequest && equalTo((V1UpdateRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1UpdateRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && records.equals(other.records) + && updateType.equals(other.updateType); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tableName, this.records, this.updateType); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional tableName = Optional.empty(); + + private Optional> records = Optional.empty(); + + private Optional updateType = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1UpdateRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + records(other.getRecords()); + updateType(other.getUpdateType()); + return this; + } + + /** + *

ID of the vault where data is being updated

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Name of the table where data is being updated

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

List of data row wise that is to be updated in the vault

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + @JsonSetter(value = "updateType", nulls = Nulls.SKIP) + public Builder updateType(Optional updateType) { + this.updateType = updateType; + return this; + } + + public Builder updateType(FlowEnumUpdateType updateType) { + this.updateType = Optional.ofNullable(updateType); + return this; + } + + public V1UpdateRequest build() { + return new V1UpdateRequest(vaultId, tableName, records, updateType, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java new file mode 100644 index 00000000..c91ad763 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java @@ -0,0 +1,96 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; +import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +public class AsyncRawRecordsClient { + protected final ClientOptions clientOptions; + + public AsyncRawRecordsClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Executes a query on the specified vault. + */ + public CompletableFuture> flowServiceExecuteQuery() { + return flowServiceExecuteQuery(V1ExecuteQueryRequest.builder().build()); + } + + /** + * Executes a query on the specified vault. + */ + public CompletableFuture> flowServiceExecuteQuery( + V1ExecuteQueryRequest request) { + return flowServiceExecuteQuery(request, null); + } + + /** + * Executes a query on the specified vault. + */ + public CompletableFuture> flowServiceExecuteQuery( + V1ExecuteQueryRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/query") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue( + responseBody.string(), V1ExecuteQueryResponse.class), + response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java new file mode 100644 index 00000000..9af54869 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java @@ -0,0 +1,51 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; +import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; + +import java.util.concurrent.CompletableFuture; + +public class AsyncRecordsClient { + protected final ClientOptions clientOptions; + + private final AsyncRawRecordsClient rawClient; + + public AsyncRecordsClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new AsyncRawRecordsClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public AsyncRawRecordsClient withRawResponse() { + return this.rawClient; + } + + /** + * Executes a query on the specified vault. + */ + public CompletableFuture flowServiceExecuteQuery() { + return this.rawClient.flowServiceExecuteQuery().thenApply(response -> response.body()); + } + + /** + * Executes a query on the specified vault. + */ + public CompletableFuture flowServiceExecuteQuery(V1ExecuteQueryRequest request) { + return this.rawClient.flowServiceExecuteQuery(request).thenApply(response -> response.body()); + } + + /** + * Executes a query on the specified vault. + */ + public CompletableFuture flowServiceExecuteQuery( + V1ExecuteQueryRequest request, RequestOptions requestOptions) { + return this.rawClient.flowServiceExecuteQuery(request, requestOptions).thenApply(response -> response.body()); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java new file mode 100644 index 00000000..cf9a1db1 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java @@ -0,0 +1,79 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; +import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; +import okhttp3.*; + +import java.io.IOException; + +public class RawRecordsClient { + protected final ClientOptions clientOptions; + + public RawRecordsClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Executes a query on the specified vault. + */ + public ApiClientHttpResponse flowServiceExecuteQuery() { + return flowServiceExecuteQuery(V1ExecuteQueryRequest.builder().build()); + } + + /** + * Executes a query on the specified vault. + */ + public ApiClientHttpResponse flowServiceExecuteQuery(V1ExecuteQueryRequest request) { + return flowServiceExecuteQuery(request, null); + } + + /** + * Executes a query on the specified vault. + */ + public ApiClientHttpResponse flowServiceExecuteQuery( + V1ExecuteQueryRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/query") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1ExecuteQueryResponse.class), + response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new ApiClientApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java new file mode 100644 index 00000000..332c0e1b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java @@ -0,0 +1,49 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; +import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; + +public class RecordsClient { + protected final ClientOptions clientOptions; + + private final RawRecordsClient rawClient; + + public RecordsClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new RawRecordsClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public RawRecordsClient withRawResponse() { + return this.rawClient; + } + + /** + * Executes a query on the specified vault. + */ + public V1ExecuteQueryResponse flowServiceExecuteQuery() { + return this.rawClient.flowServiceExecuteQuery().body(); + } + + /** + * Executes a query on the specified vault. + */ + public V1ExecuteQueryResponse flowServiceExecuteQuery(V1ExecuteQueryRequest request) { + return this.rawClient.flowServiceExecuteQuery(request).body(); + } + + /** + * Executes a query on the specified vault. + */ + public V1ExecuteQueryResponse flowServiceExecuteQuery( + V1ExecuteQueryRequest request, RequestOptions requestOptions) { + return this.rawClient.flowServiceExecuteQuery(request, requestOptions).body(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/V1ExecuteQueryRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/V1ExecuteQueryRequest.java new file mode 100644 index 00000000..2857faca --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/V1ExecuteQueryRequest.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records.requests; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1ExecuteQueryRequest.Builder.class) +public final class V1ExecuteQueryRequest { + private final Optional vaultId; + + private final Optional query; + + private final Map additionalProperties; + + private V1ExecuteQueryRequest( + Optional vaultId, Optional query, Map additionalProperties) { + this.vaultId = vaultId; + this.query = query; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault where data is being inserted + */ + @JsonProperty("vaultID") + public Optional getVaultId() { + return vaultId; + } + + /** + * @return Query to execute. + */ + @JsonProperty("query") + public Optional getQuery() { + return query; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1ExecuteQueryRequest && equalTo((V1ExecuteQueryRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1ExecuteQueryRequest other) { + return vaultId.equals(other.vaultId) && query.equals(other.query); + } + + @Override + public int hashCode() { + return Objects.hash(this.vaultId, this.query); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional vaultId = Optional.empty(); + + private Optional query = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1ExecuteQueryRequest other) { + vaultId(other.getVaultId()); + query(other.getQuery()); + return this; + } + + /** + *

ID of the vault where data is being inserted

+ */ + @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) + public Builder vaultId(Optional vaultId) { + this.vaultId = vaultId; + return this; + } + + public Builder vaultId(String vaultId) { + this.vaultId = Optional.ofNullable(vaultId); + return this; + } + + /** + *

Query to execute.

+ */ + @JsonSetter(value = "query", nulls = Nulls.SKIP) + public Builder query(Optional query) { + this.query = query; + return this; + } + + public Builder query(String query) { + this.query = Optional.ofNullable(query); + return this; + } + + public V1ExecuteQueryRequest build() { + return new V1ExecuteQueryRequest(vaultId, query, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowEnumUpdateType.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowEnumUpdateType.java new file mode 100644 index 00000000..d3c1cea0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowEnumUpdateType.java @@ -0,0 +1,24 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum FlowEnumUpdateType { + UPDATE("UPDATE"), + + REPLACE("REPLACE"); + + private final String value; + + FlowEnumUpdateType(String value) { + this.value = value; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowTokenizeResponseObjectToken.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowTokenizeResponseObjectToken.java new file mode 100644 index 00000000..0edfd9a8 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowTokenizeResponseObjectToken.java @@ -0,0 +1,188 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FlowTokenizeResponseObjectToken.Builder.class) +public final class FlowTokenizeResponseObjectToken { + private final Optional tokenGroupName; + + private final Optional token; + + private final Optional error; + + private final Optional httpCode; + + private final Map additionalProperties; + + private FlowTokenizeResponseObjectToken( + Optional tokenGroupName, + Optional token, + Optional error, + Optional httpCode, + Map additionalProperties) { + this.tokenGroupName = tokenGroupName; + this.token = token; + this.error = error; + this.httpCode = httpCode; + this.additionalProperties = additionalProperties; + } + + /** + * @return Token group Name + */ + @JsonProperty("tokenGroupName") + public Optional getTokenGroupName() { + return tokenGroupName; + } + + /** + * @return Token value + */ + @JsonProperty("token") + public Optional getToken() { + return token; + } + + /** + * @return Error if tokenization failed + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response + */ + @JsonProperty("httpCode") + public Optional getHttpCode() { + return httpCode; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FlowTokenizeResponseObjectToken && equalTo((FlowTokenizeResponseObjectToken) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FlowTokenizeResponseObjectToken other) { + return tokenGroupName.equals(other.tokenGroupName) + && token.equals(other.token) + && error.equals(other.error) + && httpCode.equals(other.httpCode); + } + + @Override + public int hashCode() { + return Objects.hash(this.tokenGroupName, this.token, this.error, this.httpCode); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional tokenGroupName = Optional.empty(); + + private Optional token = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional httpCode = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(FlowTokenizeResponseObjectToken other) { + tokenGroupName(other.getTokenGroupName()); + token(other.getToken()); + error(other.getError()); + httpCode(other.getHttpCode()); + return this; + } + + /** + *

Token group Name

+ */ + @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) + public Builder tokenGroupName(Optional tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + public Builder tokenGroupName(String tokenGroupName) { + this.tokenGroupName = Optional.ofNullable(tokenGroupName); + return this; + } + + /** + *

Token value

+ */ + @JsonSetter(value = "token", nulls = Nulls.SKIP) + public Builder token(Optional token) { + this.token = token; + return this; + } + + public Builder token(String token) { + this.token = Optional.ofNullable(token); + return this; + } + + /** + *

Error if tokenization failed

+ */ + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public Builder error(Optional error) { + this.error = error; + return this; + } + + public Builder error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

HTTP status code of the response

+ */ + @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) + public Builder httpCode(Optional httpCode) { + this.httpCode = httpCode; + return this; + } + + public Builder httpCode(Integer httpCode) { + this.httpCode = Optional.ofNullable(httpCode); + return this; + } + + public FlowTokenizeResponseObjectToken build() { + return new FlowTokenizeResponseObjectToken(tokenGroupName, token, error, httpCode, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleprotobufAny.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleprotobufAny.java new file mode 100644 index 00000000..06205978 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleprotobufAny.java @@ -0,0 +1,146 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GoogleprotobufAny.Builder.class) +public final class GoogleprotobufAny { + private final Optional type; + + private final Map additionalProperties; + + private GoogleprotobufAny(Optional type, Map additionalProperties) { + this.type = type; + this.additionalProperties = additionalProperties; + } + + /** + * @return A URL/resource name that uniquely identifies the type of the serialized + * protocol buffer message. This string must contain at least + * one "/" character. The last segment of the URL's path must represent + * the fully qualified name of the type (as in + * path/google.protobuf.Duration). The name should be in a canonical form + * (e.g., leading "." is not accepted). + *

In practice, teams usually precompile into the binary all types that they + * expect it to use in the context of Any. However, for URLs which use the + * scheme http, https, or no scheme, one can optionally set up a type + * server that maps type URLs to message definitions as follows:

+ *
    + *
  • If no scheme is provided, https is assumed.
  • + *
  • An HTTP GET on the URL must yield a [google.protobuf.Type][] + * value in binary format, or produce an error.
  • + *
  • Applications are allowed to cache lookup results based on the + * URL, or have them precompiled into a binary to avoid any + * lookup. Therefore, binary compatibility needs to be preserved + * on changes to types. (Use versioned type names to manage + * breaking changes.)
  • + *
+ *

Note: this functionality is not currently available in the official + * protobuf release, and it is not used for type URLs beginning with + * type.googleapis.com. As of May 2023, there are no widely used type server + * implementations and no plans to implement one.

+ *

Schemes other than http, https (or the empty scheme) might be + * used with implementation specific semantics.

+ */ + @JsonProperty("@type") + public Optional getType() { + return type; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GoogleprotobufAny && equalTo((GoogleprotobufAny) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GoogleprotobufAny other) { + return type.equals(other.type); + } + + @Override + public int hashCode() { + return Objects.hash(this.type); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional type = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(GoogleprotobufAny other) { + type(other.getType()); + return this; + } + + /** + *

A URL/resource name that uniquely identifies the type of the serialized + * protocol buffer message. This string must contain at least + * one "/" character. The last segment of the URL's path must represent + * the fully qualified name of the type (as in + * path/google.protobuf.Duration). The name should be in a canonical form + * (e.g., leading "." is not accepted).

+ *

In practice, teams usually precompile into the binary all types that they + * expect it to use in the context of Any. However, for URLs which use the + * scheme http, https, or no scheme, one can optionally set up a type + * server that maps type URLs to message definitions as follows:

+ *
    + *
  • If no scheme is provided, https is assumed.
  • + *
  • An HTTP GET on the URL must yield a [google.protobuf.Type][] + * value in binary format, or produce an error.
  • + *
  • Applications are allowed to cache lookup results based on the + * URL, or have them precompiled into a binary to avoid any + * lookup. Therefore, binary compatibility needs to be preserved + * on changes to types. (Use versioned type names to manage + * breaking changes.)
  • + *
+ *

Note: this functionality is not currently available in the official + * protobuf release, and it is not used for type URLs beginning with + * type.googleapis.com. As of May 2023, there are no widely used type server + * implementations and no plans to implement one.

+ *

Schemes other than http, https (or the empty scheme) might be + * used with implementation specific semantics.

+ */ + @JsonSetter(value = "@type", nulls = Nulls.SKIP) + public Builder type(Optional type) { + this.type = type; + return this; + } + + public Builder type(String type) { + this.type = Optional.ofNullable(type); + return this; + } + + public GoogleprotobufAny build() { + return new GoogleprotobufAny(type, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/RpcStatus.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/RpcStatus.java new file mode 100644 index 00000000..347ce5c4 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/RpcStatus.java @@ -0,0 +1,135 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = RpcStatus.Builder.class) +public final class RpcStatus { + private final Optional code; + + private final Optional message; + + private final Optional> details; + + private final Map additionalProperties; + + private RpcStatus( + Optional code, + Optional message, + Optional> details, + Map additionalProperties) { + this.code = code; + this.message = message; + this.details = details; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("code") + public Optional getCode() { + return code; + } + + @JsonProperty("message") + public Optional getMessage() { + return message; + } + + @JsonProperty("details") + public Optional> getDetails() { + return details; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof RpcStatus && equalTo((RpcStatus) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(RpcStatus other) { + return code.equals(other.code) && message.equals(other.message) && details.equals(other.details); + } + + @Override + public int hashCode() { + return Objects.hash(this.code, this.message, this.details); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional code = Optional.empty(); + + private Optional message = Optional.empty(); + + private Optional> details = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(RpcStatus other) { + code(other.getCode()); + message(other.getMessage()); + details(other.getDetails()); + return this; + } + + @JsonSetter(value = "code", nulls = Nulls.SKIP) + public Builder code(Optional code) { + this.code = code; + return this; + } + + public Builder code(Integer code) { + this.code = Optional.ofNullable(code); + return this; + } + + @JsonSetter(value = "message", nulls = Nulls.SKIP) + public Builder message(Optional message) { + this.message = message; + return this; + } + + public Builder message(String message) { + this.message = Optional.ofNullable(message); + return this; + } + + @JsonSetter(value = "details", nulls = Nulls.SKIP) + public Builder details(Optional> details) { + this.details = details; + return this; + } + + public Builder details(List details) { + this.details = Optional.ofNullable(details); + return this; + } + + public RpcStatus build() { + return new RpcStatus(code, message, details, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ColumnRedactions.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ColumnRedactions.java new file mode 100644 index 00000000..b467a8c0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ColumnRedactions.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1ColumnRedactions.Builder.class) +public final class V1ColumnRedactions { + private final Optional columnName; + + private final Optional redaction; + + private final Map additionalProperties; + + private V1ColumnRedactions( + Optional columnName, Optional redaction, Map additionalProperties) { + this.columnName = columnName; + this.redaction = redaction; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the column to be redacted + */ + @JsonProperty("columnName") + public Optional getColumnName() { + return columnName; + } + + /** + * @return Name of the redaction. Eg: plain_text, redacted, mask1 + */ + @JsonProperty("redaction") + public Optional getRedaction() { + return redaction; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1ColumnRedactions && equalTo((V1ColumnRedactions) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1ColumnRedactions other) { + return columnName.equals(other.columnName) && redaction.equals(other.redaction); + } + + @Override + public int hashCode() { + return Objects.hash(this.columnName, this.redaction); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional columnName = Optional.empty(); + + private Optional redaction = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1ColumnRedactions other) { + columnName(other.getColumnName()); + redaction(other.getRedaction()); + return this; + } + + /** + *

Name of the column to be redacted

+ */ + @JsonSetter(value = "columnName", nulls = Nulls.SKIP) + public Builder columnName(Optional columnName) { + this.columnName = columnName; + return this; + } + + public Builder columnName(String columnName) { + this.columnName = Optional.ofNullable(columnName); + return this; + } + + /** + *

Name of the redaction. Eg: plain_text, redacted, mask1

+ */ + @JsonSetter(value = "redaction", nulls = Nulls.SKIP) + public Builder redaction(Optional redaction) { + this.redaction = redaction; + return this; + } + + public Builder redaction(String redaction) { + this.redaction = Optional.ofNullable(redaction); + return this; + } + + public V1ColumnRedactions build() { + return new V1ColumnRedactions(columnName, redaction, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponse.java new file mode 100644 index 00000000..24bd865d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponse.java @@ -0,0 +1,93 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1DeleteResponse.Builder.class) +public final class V1DeleteResponse { + private final Optional> records; + + private final Map additionalProperties; + + private V1DeleteResponse(Optional> records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of deleted records with skyflow ID and any partial errors. + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1DeleteResponse && equalTo((V1DeleteResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1DeleteResponse other) { + return records.equals(other.records); + } + + @Override + public int hashCode() { + return Objects.hash(this.records); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> records = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1DeleteResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of deleted records with skyflow ID and any partial errors.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + public V1DeleteResponse build() { + return new V1DeleteResponse(records, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponseObject.java new file mode 100644 index 00000000..087ce4c7 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponseObject.java @@ -0,0 +1,156 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1DeleteResponseObject.Builder.class) +public final class V1DeleteResponseObject { + private final Optional skyflowId; + + private final Optional error; + + private final Optional httpCode; + + private final Map additionalProperties; + + private V1DeleteResponseObject( + Optional skyflowId, + Optional error, + Optional httpCode, + Map additionalProperties) { + this.skyflowId = skyflowId; + this.error = error; + this.httpCode = httpCode; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID for the deleted record + */ + @JsonProperty("skyflowID") + public Optional getSkyflowId() { + return skyflowId; + } + + /** + * @return Partial Error message if any + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response + */ + @JsonProperty("httpCode") + public Optional getHttpCode() { + return httpCode; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1DeleteResponseObject && equalTo((V1DeleteResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1DeleteResponseObject other) { + return skyflowId.equals(other.skyflowId) && error.equals(other.error) && httpCode.equals(other.httpCode); + } + + @Override + public int hashCode() { + return Objects.hash(this.skyflowId, this.error, this.httpCode); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional skyflowId = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional httpCode = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1DeleteResponseObject other) { + skyflowId(other.getSkyflowId()); + error(other.getError()); + httpCode(other.getHttpCode()); + return this; + } + + /** + *

Skyflow ID for the deleted record

+ */ + @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) + public Builder skyflowId(Optional skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + public Builder skyflowId(String skyflowId) { + this.skyflowId = Optional.ofNullable(skyflowId); + return this; + } + + /** + *

Partial Error message if any

+ */ + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public Builder error(Optional error) { + this.error = error; + return this; + } + + public Builder error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

HTTP status code of the response

+ */ + @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) + public Builder httpCode(Optional httpCode) { + this.httpCode = httpCode; + return this; + } + + public Builder httpCode(Integer httpCode) { + this.httpCode = Optional.ofNullable(httpCode); + return this; + } + + public V1DeleteResponseObject build() { + return new V1DeleteResponseObject(skyflowId, error, httpCode, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteTokenResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteTokenResponseObject.java new file mode 100644 index 00000000..f2e1dacd --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteTokenResponseObject.java @@ -0,0 +1,156 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1DeleteTokenResponseObject.Builder.class) +public final class V1DeleteTokenResponseObject { + private final Optional value; + + private final Optional error; + + private final Optional httpCode; + + private final Map additionalProperties; + + private V1DeleteTokenResponseObject( + Optional value, + Optional error, + Optional httpCode, + Map additionalProperties) { + this.value = value; + this.error = error; + this.httpCode = httpCode; + this.additionalProperties = additionalProperties; + } + + /** + * @return Token value + */ + @JsonProperty("value") + public Optional getValue() { + return value; + } + + /** + * @return Error if deletion failed + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response + */ + @JsonProperty("httpCode") + public Optional getHttpCode() { + return httpCode; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1DeleteTokenResponseObject && equalTo((V1DeleteTokenResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1DeleteTokenResponseObject other) { + return value.equals(other.value) && error.equals(other.error) && httpCode.equals(other.httpCode); + } + + @Override + public int hashCode() { + return Objects.hash(this.value, this.error, this.httpCode); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional value = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional httpCode = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1DeleteTokenResponseObject other) { + value(other.getValue()); + error(other.getError()); + httpCode(other.getHttpCode()); + return this; + } + + /** + *

Token value

+ */ + @JsonSetter(value = "value", nulls = Nulls.SKIP) + public Builder value(Optional value) { + this.value = value; + return this; + } + + public Builder value(String value) { + this.value = Optional.ofNullable(value); + return this; + } + + /** + *

Error if deletion failed

+ */ + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public Builder error(Optional error) { + this.error = error; + return this; + } + + public Builder error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

HTTP status code of the response

+ */ + @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) + public Builder httpCode(Optional httpCode) { + this.httpCode = httpCode; + return this; + } + + public Builder httpCode(Integer httpCode) { + this.httpCode = Optional.ofNullable(httpCode); + return this; + } + + public V1DeleteTokenResponseObject build() { + return new V1DeleteTokenResponseObject(value, error, httpCode, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryRecordResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryRecordResponse.java new file mode 100644 index 00000000..9de3418b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryRecordResponse.java @@ -0,0 +1,96 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1ExecuteQueryRecordResponse.Builder.class) +public final class V1ExecuteQueryRecordResponse { + private final Optional> data; + + private final Map additionalProperties; + + private V1ExecuteQueryRecordResponse(Optional> data, Map additionalProperties) { + this.data = data; + this.additionalProperties = additionalProperties; + } + + /** + * @return Fields and values for the record. For example, {'field_1':'value_1', 'field_2':'value_2'}. + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1ExecuteQueryRecordResponse && equalTo((V1ExecuteQueryRecordResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1ExecuteQueryRecordResponse other) { + return data.equals(other.data); + } + + @Override + public int hashCode() { + return Objects.hash(this.data); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> data = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1ExecuteQueryRecordResponse other) { + data(other.getData()); + return this; + } + + /** + *

Fields and values for the record. For example, {'field_1':'value_1', 'field_2':'value_2'}.

+ */ + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Optional> data) { + this.data = data; + return this; + } + + public Builder data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + public V1ExecuteQueryRecordResponse build() { + return new V1ExecuteQueryRecordResponse(data, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponse.java new file mode 100644 index 00000000..f80b54e0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponse.java @@ -0,0 +1,118 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1ExecuteQueryResponse.Builder.class) +public final class V1ExecuteQueryResponse { + private final Optional> records; + + private final Optional metadata; + + private final Map additionalProperties; + + private V1ExecuteQueryResponse( + Optional> records, + Optional metadata, + Map additionalProperties) { + this.records = records; + this.metadata = metadata; + this.additionalProperties = additionalProperties; + } + + /** + * @return Records corresponding to the specified query. + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @JsonProperty("metadata") + public Optional getMetadata() { + return metadata; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1ExecuteQueryResponse && equalTo((V1ExecuteQueryResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1ExecuteQueryResponse other) { + return records.equals(other.records) && metadata.equals(other.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(this.records, this.metadata); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> records = Optional.empty(); + + private Optional metadata = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1ExecuteQueryResponse other) { + records(other.getRecords()); + metadata(other.getMetadata()); + return this; + } + + /** + *

Records corresponding to the specified query.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + @JsonSetter(value = "metadata", nulls = Nulls.SKIP) + public Builder metadata(Optional metadata) { + this.metadata = metadata; + return this; + } + + public Builder metadata(V1ExecuteQueryResponseMetadata metadata) { + this.metadata = Optional.ofNullable(metadata); + return this; + } + + public V1ExecuteQueryResponse build() { + return new V1ExecuteQueryResponse(records, metadata, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponseMetadata.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponseMetadata.java new file mode 100644 index 00000000..c23da3bd --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponseMetadata.java @@ -0,0 +1,93 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1ExecuteQueryResponseMetadata.Builder.class) +public final class V1ExecuteQueryResponseMetadata { + private final Optional> columns; + + private final Map additionalProperties; + + private V1ExecuteQueryResponseMetadata(Optional> columns, Map additionalProperties) { + this.columns = columns; + this.additionalProperties = additionalProperties; + } + + /** + * @return Return columns for the query + */ + @JsonProperty("columns") + public Optional> getColumns() { + return columns; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1ExecuteQueryResponseMetadata && equalTo((V1ExecuteQueryResponseMetadata) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1ExecuteQueryResponseMetadata other) { + return columns.equals(other.columns); + } + + @Override + public int hashCode() { + return Objects.hash(this.columns); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> columns = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1ExecuteQueryResponseMetadata other) { + columns(other.getColumns()); + return this; + } + + /** + *

Return columns for the query

+ */ + @JsonSetter(value = "columns", nulls = Nulls.SKIP) + public Builder columns(Optional> columns) { + this.columns = columns; + return this; + } + + public Builder columns(List columns) { + this.columns = Optional.ofNullable(columns); + return this; + } + + public V1ExecuteQueryResponseMetadata build() { + return new V1ExecuteQueryResponseMetadata(columns, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDeleteTokenResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDeleteTokenResponse.java new file mode 100644 index 00000000..34ca245c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDeleteTokenResponse.java @@ -0,0 +1,94 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowDeleteTokenResponse.Builder.class) +public final class V1FlowDeleteTokenResponse { + private final Optional> tokens; + + private final Map additionalProperties; + + private V1FlowDeleteTokenResponse( + Optional> tokens, Map additionalProperties) { + this.tokens = tokens; + this.additionalProperties = additionalProperties; + } + + /** + * @return Tokens data for Delete + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowDeleteTokenResponse && equalTo((V1FlowDeleteTokenResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowDeleteTokenResponse other) { + return tokens.equals(other.tokens); + } + + @Override + public int hashCode() { + return Objects.hash(this.tokens); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> tokens = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowDeleteTokenResponse other) { + tokens(other.getTokens()); + return this; + } + + /** + *

Tokens data for Delete

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + public Builder tokens(List tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + public V1FlowDeleteTokenResponse build() { + return new V1FlowDeleteTokenResponse(tokens, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponse.java new file mode 100644 index 00000000..defe1dad --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponse.java @@ -0,0 +1,94 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowDetokenizeResponse.Builder.class) +public final class V1FlowDetokenizeResponse { + private final Optional> response; + + private final Map additionalProperties; + + private V1FlowDetokenizeResponse( + Optional> response, Map additionalProperties) { + this.response = response; + this.additionalProperties = additionalProperties; + } + + /** + * @return Detokenized data + */ + @JsonProperty("response") + public Optional> getResponse() { + return response; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowDetokenizeResponse && equalTo((V1FlowDetokenizeResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowDetokenizeResponse other) { + return response.equals(other.response); + } + + @Override + public int hashCode() { + return Objects.hash(this.response); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> response = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowDetokenizeResponse other) { + response(other.getResponse()); + return this; + } + + /** + *

Detokenized data

+ */ + @JsonSetter(value = "response", nulls = Nulls.SKIP) + public Builder response(Optional> response) { + this.response = response; + return this; + } + + public Builder response(List response) { + this.response = Optional.ofNullable(response); + return this; + } + + public V1FlowDetokenizeResponse build() { + return new V1FlowDetokenizeResponse(response, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponseObject.java new file mode 100644 index 00000000..f0cf909d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponseObject.java @@ -0,0 +1,249 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowDetokenizeResponseObject.Builder.class) +public final class V1FlowDetokenizeResponseObject { + private final Optional token; + + private final Optional value; + + private final Optional tokenGroupName; + + private final Optional error; + + private final Optional httpCode; + + private final Optional> metadata; + + private final Map additionalProperties; + + private V1FlowDetokenizeResponseObject( + Optional token, + Optional value, + Optional tokenGroupName, + Optional error, + Optional httpCode, + Optional> metadata, + Map additionalProperties) { + this.token = token; + this.value = value; + this.tokenGroupName = tokenGroupName; + this.error = error; + this.httpCode = httpCode; + this.metadata = metadata; + this.additionalProperties = additionalProperties; + } + + /** + * @return Token to be detokenized + */ + @JsonProperty("token") + public Optional getToken() { + return token; + } + + /** + * @return Detokenized value for the token + */ + @JsonProperty("value") + public Optional getValue() { + return value; + } + + /** + * @return Token group name + */ + @JsonProperty("tokenGroupName") + public Optional getTokenGroupName() { + return tokenGroupName; + } + + /** + * @return Error if detokenization failed + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response + */ + @JsonProperty("httpCode") + public Optional getHttpCode() { + return httpCode; + } + + /** + * @return Additional metadata associated with the token, such as tableName or skyflowID + */ + @JsonProperty("metadata") + public Optional> getMetadata() { + return metadata; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowDetokenizeResponseObject && equalTo((V1FlowDetokenizeResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowDetokenizeResponseObject other) { + return token.equals(other.token) + && value.equals(other.value) + && tokenGroupName.equals(other.tokenGroupName) + && error.equals(other.error) + && httpCode.equals(other.httpCode) + && metadata.equals(other.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(this.token, this.value, this.tokenGroupName, this.error, this.httpCode, this.metadata); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional token = Optional.empty(); + + private Optional value = Optional.empty(); + + private Optional tokenGroupName = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional httpCode = Optional.empty(); + + private Optional> metadata = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowDetokenizeResponseObject other) { + token(other.getToken()); + value(other.getValue()); + tokenGroupName(other.getTokenGroupName()); + error(other.getError()); + httpCode(other.getHttpCode()); + metadata(other.getMetadata()); + return this; + } + + /** + *

Token to be detokenized

+ */ + @JsonSetter(value = "token", nulls = Nulls.SKIP) + public Builder token(Optional token) { + this.token = token; + return this; + } + + public Builder token(String token) { + this.token = Optional.ofNullable(token); + return this; + } + + /** + *

Detokenized value for the token

+ */ + @JsonSetter(value = "value", nulls = Nulls.SKIP) + public Builder value(Optional value) { + this.value = value; + return this; + } + + public Builder value(Object value) { + this.value = Optional.ofNullable(value); + return this; + } + + /** + *

Token group name

+ */ + @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) + public Builder tokenGroupName(Optional tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + public Builder tokenGroupName(String tokenGroupName) { + this.tokenGroupName = Optional.ofNullable(tokenGroupName); + return this; + } + + /** + *

Error if detokenization failed

+ */ + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public Builder error(Optional error) { + this.error = error; + return this; + } + + public Builder error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

HTTP status code of the response

+ */ + @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) + public Builder httpCode(Optional httpCode) { + this.httpCode = httpCode; + return this; + } + + public Builder httpCode(Integer httpCode) { + this.httpCode = Optional.ofNullable(httpCode); + return this; + } + + /** + *

Additional metadata associated with the token, such as tableName or skyflowID

+ */ + @JsonSetter(value = "metadata", nulls = Nulls.SKIP) + public Builder metadata(Optional> metadata) { + this.metadata = metadata; + return this; + } + + public Builder metadata(Map metadata) { + this.metadata = Optional.ofNullable(metadata); + return this; + } + + public V1FlowDetokenizeResponseObject build() { + return new V1FlowDetokenizeResponseObject( + token, value, tokenGroupName, error, httpCode, metadata, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeRequestObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeRequestObject.java new file mode 100644 index 00000000..adefcaed --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeRequestObject.java @@ -0,0 +1,153 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowTokenizeRequestObject.Builder.class) +public final class V1FlowTokenizeRequestObject { + private final Optional value; + + private final Optional> tokenGroupNames; + + private final Optional token; + + private final Map additionalProperties; + + private V1FlowTokenizeRequestObject( + Optional value, + Optional> tokenGroupNames, + Optional token, + Map additionalProperties) { + this.value = value; + this.tokenGroupNames = tokenGroupNames; + this.token = token; + this.additionalProperties = additionalProperties; + } + + /** + * @return Token Value + */ + @JsonProperty("value") + public Optional getValue() { + return value; + } + + /** + * @return List of token group names + */ + @JsonProperty("tokenGroupNames") + public Optional> getTokenGroupNames() { + return tokenGroupNames; + } + + /** + * @return Token for the value, in case of BYOT. + */ + @JsonProperty("token") + public Optional getToken() { + return token; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowTokenizeRequestObject && equalTo((V1FlowTokenizeRequestObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowTokenizeRequestObject other) { + return value.equals(other.value) && tokenGroupNames.equals(other.tokenGroupNames) && token.equals(other.token); + } + + @Override + public int hashCode() { + return Objects.hash(this.value, this.tokenGroupNames, this.token); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional value = Optional.empty(); + + private Optional> tokenGroupNames = Optional.empty(); + + private Optional token = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowTokenizeRequestObject other) { + value(other.getValue()); + tokenGroupNames(other.getTokenGroupNames()); + token(other.getToken()); + return this; + } + + /** + *

Token Value

+ */ + @JsonSetter(value = "value", nulls = Nulls.SKIP) + public Builder value(Optional value) { + this.value = value; + return this; + } + + public Builder value(Object value) { + this.value = Optional.ofNullable(value); + return this; + } + + /** + *

List of token group names

+ */ + @JsonSetter(value = "tokenGroupNames", nulls = Nulls.SKIP) + public Builder tokenGroupNames(Optional> tokenGroupNames) { + this.tokenGroupNames = tokenGroupNames; + return this; + } + + public Builder tokenGroupNames(List tokenGroupNames) { + this.tokenGroupNames = Optional.ofNullable(tokenGroupNames); + return this; + } + + /** + *

Token for the value, in case of BYOT.

+ */ + @JsonSetter(value = "token", nulls = Nulls.SKIP) + public Builder token(Optional token) { + this.token = token; + return this; + } + + public Builder token(Object token) { + this.token = Optional.ofNullable(token); + return this; + } + + public V1FlowTokenizeRequestObject build() { + return new V1FlowTokenizeRequestObject(value, tokenGroupNames, token, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponse.java new file mode 100644 index 00000000..cf071b86 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponse.java @@ -0,0 +1,94 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowTokenizeResponse.Builder.class) +public final class V1FlowTokenizeResponse { + private final Optional> response; + + private final Map additionalProperties; + + private V1FlowTokenizeResponse( + Optional> response, Map additionalProperties) { + this.response = response; + this.additionalProperties = additionalProperties; + } + + /** + * @return Tokenized data + */ + @JsonProperty("response") + public Optional> getResponse() { + return response; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowTokenizeResponse && equalTo((V1FlowTokenizeResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowTokenizeResponse other) { + return response.equals(other.response); + } + + @Override + public int hashCode() { + return Objects.hash(this.response); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> response = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowTokenizeResponse other) { + response(other.getResponse()); + return this; + } + + /** + *

Tokenized data

+ */ + @JsonSetter(value = "response", nulls = Nulls.SKIP) + public Builder response(Optional> response) { + this.response = response; + return this; + } + + public Builder response(List response) { + this.response = Optional.ofNullable(response); + return this; + } + + public V1FlowTokenizeResponse build() { + return new V1FlowTokenizeResponse(response, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponseObject.java new file mode 100644 index 00000000..eb4a15ac --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponseObject.java @@ -0,0 +1,124 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowTokenizeResponseObject.Builder.class) +public final class V1FlowTokenizeResponseObject { + private final Optional value; + + private final Optional> tokens; + + private final Map additionalProperties; + + private V1FlowTokenizeResponseObject( + Optional value, + Optional> tokens, + Map additionalProperties) { + this.value = value; + this.tokens = tokens; + this.additionalProperties = additionalProperties; + } + + /** + * @return Value of token + */ + @JsonProperty("value") + public Optional getValue() { + return value; + } + + /** + * @return Token value + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowTokenizeResponseObject && equalTo((V1FlowTokenizeResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowTokenizeResponseObject other) { + return value.equals(other.value) && tokens.equals(other.tokens); + } + + @Override + public int hashCode() { + return Objects.hash(this.value, this.tokens); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional value = Optional.empty(); + + private Optional> tokens = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowTokenizeResponseObject other) { + value(other.getValue()); + tokens(other.getTokens()); + return this; + } + + /** + *

Value of token

+ */ + @JsonSetter(value = "value", nulls = Nulls.SKIP) + public Builder value(Optional value) { + this.value = value; + return this; + } + + public Builder value(Object value) { + this.value = Optional.ofNullable(value); + return this; + } + + /** + *

Token value

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + public Builder tokens(List tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + public V1FlowTokenizeResponseObject build() { + return new V1FlowTokenizeResponseObject(value, tokens, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsData.java new file mode 100644 index 00000000..5345de38 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsData.java @@ -0,0 +1,96 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowVaultMetricsData.Builder.class) +public final class V1FlowVaultMetricsData { + private final Optional> tables; + + private final Map additionalProperties; + + private V1FlowVaultMetricsData(Optional> tables, Map additionalProperties) { + this.tables = tables; + this.additionalProperties = additionalProperties; + } + + /** + * @return Map of table names to their metrics + */ + @JsonProperty("tables") + public Optional> getTables() { + return tables; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowVaultMetricsData && equalTo((V1FlowVaultMetricsData) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowVaultMetricsData other) { + return tables.equals(other.tables); + } + + @Override + public int hashCode() { + return Objects.hash(this.tables); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> tables = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowVaultMetricsData other) { + tables(other.getTables()); + return this; + } + + /** + *

Map of table names to their metrics

+ */ + @JsonSetter(value = "tables", nulls = Nulls.SKIP) + public Builder tables(Optional> tables) { + this.tables = tables; + return this; + } + + public Builder tables(Map tables) { + this.tables = Optional.ofNullable(tables); + return this; + } + + public V1FlowVaultMetricsData build() { + return new V1FlowVaultMetricsData(tables, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsResponse.java new file mode 100644 index 00000000..f933bce5 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsResponse.java @@ -0,0 +1,121 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1FlowVaultMetricsResponse.Builder.class) +public final class V1FlowVaultMetricsResponse { + private final Optional data; + + private final Optional> error; + + private final Map additionalProperties; + + private V1FlowVaultMetricsResponse( + Optional data, + Optional> error, + Map additionalProperties) { + this.data = data; + this.error = error; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("data") + public Optional getData() { + return data; + } + + /** + * @return Error information, if any + */ + @JsonProperty("error") + public Optional> getError() { + return error; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1FlowVaultMetricsResponse && equalTo((V1FlowVaultMetricsResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1FlowVaultMetricsResponse other) { + return data.equals(other.data) && error.equals(other.error); + } + + @Override + public int hashCode() { + return Objects.hash(this.data, this.error); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional data = Optional.empty(); + + private Optional> error = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1FlowVaultMetricsResponse other) { + data(other.getData()); + error(other.getError()); + return this; + } + + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Optional data) { + this.data = data; + return this; + } + + public Builder data(V1FlowVaultMetricsData data) { + this.data = Optional.ofNullable(data); + return this; + } + + /** + *

Error information, if any

+ */ + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public Builder error(Optional> error) { + this.error = error; + return this; + } + + public Builder error(Map error) { + this.error = Optional.ofNullable(error); + return this; + } + + public V1FlowVaultMetricsResponse build() { + return new V1FlowVaultMetricsResponse(data, error, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetRequestData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetRequestData.java new file mode 100644 index 00000000..0c0cfab9 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetRequestData.java @@ -0,0 +1,216 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1GetRequestData.Builder.class) +public final class V1GetRequestData { + private final Optional tableName; + + private final Optional> skyflowIDs; + + private final Optional> columnRedactions; + + private final Optional> columns; + + private final Optional> uniqueValues; + + private final Map additionalProperties; + + private V1GetRequestData( + Optional tableName, + Optional> skyflowIDs, + Optional> columnRedactions, + Optional> columns, + Optional> uniqueValues, + Map additionalProperties) { + this.tableName = tableName; + this.skyflowIDs = skyflowIDs; + this.columnRedactions = columnRedactions; + this.columns = columns; + this.uniqueValues = uniqueValues; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the table where data is being fetched + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return Skyflow ID for the record to be fetched + */ + @JsonProperty("skyflowIDs") + public Optional> getSkyflowIDs() { + return skyflowIDs; + } + + /** + * @return List of columns to be redacted. + */ + @JsonProperty("columnRedactions") + public Optional> getColumnRedactions() { + return columnRedactions; + } + + /** + * @return List of columns to be fetched. + */ + @JsonProperty("columns") + public Optional> getColumns() { + return columns; + } + + /** + * @return List of unique constraint values to query records by data + */ + @JsonProperty("uniqueValues") + public Optional> getUniqueValues() { + return uniqueValues; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1GetRequestData && equalTo((V1GetRequestData) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1GetRequestData other) { + return tableName.equals(other.tableName) + && skyflowIDs.equals(other.skyflowIDs) + && columnRedactions.equals(other.columnRedactions) + && columns.equals(other.columns) + && uniqueValues.equals(other.uniqueValues); + } + + @Override + public int hashCode() { + return Objects.hash(this.tableName, this.skyflowIDs, this.columnRedactions, this.columns, this.uniqueValues); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional tableName = Optional.empty(); + + private Optional> skyflowIDs = Optional.empty(); + + private Optional> columnRedactions = Optional.empty(); + + private Optional> columns = Optional.empty(); + + private Optional> uniqueValues = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1GetRequestData other) { + tableName(other.getTableName()); + skyflowIDs(other.getSkyflowIDs()); + columnRedactions(other.getColumnRedactions()); + columns(other.getColumns()); + uniqueValues(other.getUniqueValues()); + return this; + } + + /** + *

Name of the table where data is being fetched

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

Skyflow ID for the record to be fetched

+ */ + @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) + public Builder skyflowIDs(Optional> skyflowIDs) { + this.skyflowIDs = skyflowIDs; + return this; + } + + public Builder skyflowIDs(List skyflowIDs) { + this.skyflowIDs = Optional.ofNullable(skyflowIDs); + return this; + } + + /** + *

List of columns to be redacted.

+ */ + @JsonSetter(value = "columnRedactions", nulls = Nulls.SKIP) + public Builder columnRedactions(Optional> columnRedactions) { + this.columnRedactions = columnRedactions; + return this; + } + + public Builder columnRedactions(List columnRedactions) { + this.columnRedactions = Optional.ofNullable(columnRedactions); + return this; + } + + /** + *

List of columns to be fetched.

+ */ + @JsonSetter(value = "columns", nulls = Nulls.SKIP) + public Builder columns(Optional> columns) { + this.columns = columns; + return this; + } + + public Builder columns(List columns) { + this.columns = Optional.ofNullable(columns); + return this; + } + + /** + *

List of unique constraint values to query records by data

+ */ + @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) + public Builder uniqueValues(Optional> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + public Builder uniqueValues(List uniqueValues) { + this.uniqueValues = Optional.ofNullable(uniqueValues); + return this; + } + + public V1GetRequestData build() { + return new V1GetRequestData( + tableName, skyflowIDs, columnRedactions, columns, uniqueValues, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetResponse.java new file mode 100644 index 00000000..a64a7588 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetResponse.java @@ -0,0 +1,93 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1GetResponse.Builder.class) +public final class V1GetResponse { + private final Optional> records; + + private final Map additionalProperties; + + private V1GetResponse(Optional> records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of fetched records with skyflow ID, tokens, data, and any partial errors + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1GetResponse && equalTo((V1GetResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1GetResponse other) { + return records.equals(other.records); + } + + @Override + public int hashCode() { + return Objects.hash(this.records); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> records = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1GetResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of fetched records with skyflow ID, tokens, data, and any partial errors

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + public V1GetResponse build() { + return new V1GetResponse(records, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordData.java new file mode 100644 index 00000000..7de162cc --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordData.java @@ -0,0 +1,182 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1InsertRecordData.Builder.class) +public final class V1InsertRecordData { + private final Optional> data; + + private final Optional> tokens; + + private final Optional tableName; + + private final Optional upsert; + + private final Map additionalProperties; + + private V1InsertRecordData( + Optional> data, + Optional> tokens, + Optional tableName, + Optional upsert, + Map additionalProperties) { + this.data = data; + this.tokens = tokens; + this.tableName = tableName; + this.upsert = upsert; + this.additionalProperties = additionalProperties; + } + + /** + * @return Columns names and values + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + /** + * @return undocumented_field; Tokens data for the columns if any + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + /** + * @return Table name for the record + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + @JsonProperty("upsert") + public Optional getUpsert() { + return upsert; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1InsertRecordData && equalTo((V1InsertRecordData) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1InsertRecordData other) { + return data.equals(other.data) + && tokens.equals(other.tokens) + && tableName.equals(other.tableName) + && upsert.equals(other.upsert); + } + + @Override + public int hashCode() { + return Objects.hash(this.data, this.tokens, this.tableName, this.upsert); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> data = Optional.empty(); + + private Optional> tokens = Optional.empty(); + + private Optional tableName = Optional.empty(); + + private Optional upsert = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1InsertRecordData other) { + data(other.getData()); + tokens(other.getTokens()); + tableName(other.getTableName()); + upsert(other.getUpsert()); + return this; + } + + /** + *

Columns names and values

+ */ + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Optional> data) { + this.data = data; + return this; + } + + public Builder data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + /** + *

undocumented_field; Tokens data for the columns if any

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + public Builder tokens(Map tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + /** + *

Table name for the record

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + @JsonSetter(value = "upsert", nulls = Nulls.SKIP) + public Builder upsert(Optional upsert) { + this.upsert = upsert; + return this; + } + + public Builder upsert(V1Upsert upsert) { + this.upsert = Optional.ofNullable(upsert); + return this; + } + + public V1InsertRecordData build() { + return new V1InsertRecordData(data, tokens, tableName, upsert, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertResponse.java new file mode 100644 index 00000000..4ff3ff2d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertResponse.java @@ -0,0 +1,93 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1InsertResponse.Builder.class) +public final class V1InsertResponse { + private final Optional> records; + + private final Map additionalProperties; + + private V1InsertResponse(Optional> records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of inserted records with skyflow ID, tokens, data, and any partial errors. + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1InsertResponse && equalTo((V1InsertResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1InsertResponse other) { + return records.equals(other.records); + } + + @Override + public int hashCode() { + return Objects.hash(this.records); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> records = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1InsertResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of inserted records with skyflow ID, tokens, data, and any partial errors.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + public V1InsertResponse build() { + return new V1InsertResponse(records, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1RecordResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1RecordResponseObject.java new file mode 100644 index 00000000..b6c2467c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1RecordResponseObject.java @@ -0,0 +1,280 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1RecordResponseObject.Builder.class) +public final class V1RecordResponseObject { + private final Optional skyflowId; + + private final Optional> tokens; + + private final Optional> data; + + private final Optional> hashedData; + + private final Optional error; + + private final Optional httpCode; + + private final Optional tableName; + + private final Map additionalProperties; + + private V1RecordResponseObject( + Optional skyflowId, + Optional> tokens, + Optional> data, + Optional> hashedData, + Optional error, + Optional httpCode, + Optional tableName, + Map additionalProperties) { + this.skyflowId = skyflowId; + this.tokens = tokens; + this.data = data; + this.hashedData = hashedData; + this.error = error; + this.httpCode = httpCode; + this.tableName = tableName; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID for the inserted record + */ + @JsonProperty("skyflowID") + public Optional getSkyflowId() { + return skyflowId; + } + + /** + * @return Tokens data for the columns if any + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + /** + * @return Columns names and values + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + /** + * @return Hashed Data for the columns if any + */ + @JsonProperty("hashedData") + public Optional> getHashedData() { + return hashedData; + } + + /** + * @return Partial Error message if any + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response + */ + @JsonProperty("httpCode") + public Optional getHttpCode() { + return httpCode; + } + + /** + * @return Name of the table record belongs to + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1RecordResponseObject && equalTo((V1RecordResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1RecordResponseObject other) { + return skyflowId.equals(other.skyflowId) + && tokens.equals(other.tokens) + && data.equals(other.data) + && hashedData.equals(other.hashedData) + && error.equals(other.error) + && httpCode.equals(other.httpCode) + && tableName.equals(other.tableName); + } + + @Override + public int hashCode() { + return Objects.hash( + this.skyflowId, this.tokens, this.data, this.hashedData, this.error, this.httpCode, this.tableName); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional skyflowId = Optional.empty(); + + private Optional> tokens = Optional.empty(); + + private Optional> data = Optional.empty(); + + private Optional> hashedData = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional httpCode = Optional.empty(); + + private Optional tableName = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1RecordResponseObject other) { + skyflowId(other.getSkyflowId()); + tokens(other.getTokens()); + data(other.getData()); + hashedData(other.getHashedData()); + error(other.getError()); + httpCode(other.getHttpCode()); + tableName(other.getTableName()); + return this; + } + + /** + *

Skyflow ID for the inserted record

+ */ + @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) + public Builder skyflowId(Optional skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + public Builder skyflowId(String skyflowId) { + this.skyflowId = Optional.ofNullable(skyflowId); + return this; + } + + /** + *

Tokens data for the columns if any

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + public Builder tokens(Map tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + /** + *

Columns names and values

+ */ + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Optional> data) { + this.data = data; + return this; + } + + public Builder data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + /** + *

Hashed Data for the columns if any

+ */ + @JsonSetter(value = "hashedData", nulls = Nulls.SKIP) + public Builder hashedData(Optional> hashedData) { + this.hashedData = hashedData; + return this; + } + + public Builder hashedData(Map hashedData) { + this.hashedData = Optional.ofNullable(hashedData); + return this; + } + + /** + *

Partial Error message if any

+ */ + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public Builder error(Optional error) { + this.error = error; + return this; + } + + public Builder error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

HTTP status code of the response

+ */ + @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) + public Builder httpCode(Optional httpCode) { + this.httpCode = httpCode; + return this; + } + + public Builder httpCode(Integer httpCode) { + this.httpCode = Optional.ofNullable(httpCode); + return this; + } + + /** + *

Name of the table record belongs to

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + public V1RecordResponseObject build() { + return new V1RecordResponseObject( + skyflowId, tokens, data, hashedData, error, httpCode, tableName, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1TokenGroupRedactions.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1TokenGroupRedactions.java new file mode 100644 index 00000000..5d5fc97f --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1TokenGroupRedactions.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1TokenGroupRedactions.Builder.class) +public final class V1TokenGroupRedactions { + private final Optional tokenGroupName; + + private final Optional redaction; + + private final Map additionalProperties; + + private V1TokenGroupRedactions( + Optional tokenGroupName, Optional redaction, Map additionalProperties) { + this.tokenGroupName = tokenGroupName; + this.redaction = redaction; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the token group to be redacted + */ + @JsonProperty("tokenGroupName") + public Optional getTokenGroupName() { + return tokenGroupName; + } + + /** + * @return Name of the redaction. Eg: plain_text, redacted, mask1 + */ + @JsonProperty("redaction") + public Optional getRedaction() { + return redaction; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1TokenGroupRedactions && equalTo((V1TokenGroupRedactions) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1TokenGroupRedactions other) { + return tokenGroupName.equals(other.tokenGroupName) && redaction.equals(other.redaction); + } + + @Override + public int hashCode() { + return Objects.hash(this.tokenGroupName, this.redaction); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional tokenGroupName = Optional.empty(); + + private Optional redaction = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1TokenGroupRedactions other) { + tokenGroupName(other.getTokenGroupName()); + redaction(other.getRedaction()); + return this; + } + + /** + *

Name of the token group to be redacted

+ */ + @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) + public Builder tokenGroupName(Optional tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + public Builder tokenGroupName(String tokenGroupName) { + this.tokenGroupName = Optional.ofNullable(tokenGroupName); + return this; + } + + /** + *

Name of the redaction. Eg: plain_text, redacted, mask1

+ */ + @JsonSetter(value = "redaction", nulls = Nulls.SKIP) + public Builder redaction(Optional redaction) { + this.redaction = redaction; + return this; + } + + public Builder redaction(String redaction) { + this.redaction = Optional.ofNullable(redaction); + return this; + } + + public V1TokenGroupRedactions build() { + return new V1TokenGroupRedactions(tokenGroupName, redaction, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UniqueValue.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UniqueValue.java new file mode 100644 index 00000000..3b188c6d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UniqueValue.java @@ -0,0 +1,96 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1UniqueValue.Builder.class) +public final class V1UniqueValue { + private final Optional> data; + + private final Map additionalProperties; + + private V1UniqueValue(Optional> data, Map additionalProperties) { + this.data = data; + this.additionalProperties = additionalProperties; + } + + /** + * @return Columns names and values for unique value entry + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1UniqueValue && equalTo((V1UniqueValue) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1UniqueValue other) { + return data.equals(other.data); + } + + @Override + public int hashCode() { + return Objects.hash(this.data); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> data = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1UniqueValue other) { + data(other.getData()); + return this; + } + + /** + *

Columns names and values for unique value entry

+ */ + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Optional> data) { + this.data = data; + return this; + } + + public Builder data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + public V1UniqueValue build() { + return new V1UniqueValue(data, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordData.java new file mode 100644 index 00000000..5a904005 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordData.java @@ -0,0 +1,188 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1UpdateRecordData.Builder.class) +public final class V1UpdateRecordData { + private final Optional skyflowId; + + private final Optional> data; + + private final Optional> tokens; + + private final Optional tableName; + + private final Map additionalProperties; + + private V1UpdateRecordData( + Optional skyflowId, + Optional> data, + Optional> tokens, + Optional tableName, + Map additionalProperties) { + this.skyflowId = skyflowId; + this.data = data; + this.tokens = tokens; + this.tableName = tableName; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID for the record to be updated + */ + @JsonProperty("skyflowID") + public Optional getSkyflowId() { + return skyflowId; + } + + /** + * @return List of data row wise that is to be updated in the vault + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + /** + * @return undocumented_field; Tokens data for the columns if any + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + /** + * @return Table name for the record + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1UpdateRecordData && equalTo((V1UpdateRecordData) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1UpdateRecordData other) { + return skyflowId.equals(other.skyflowId) + && data.equals(other.data) + && tokens.equals(other.tokens) + && tableName.equals(other.tableName); + } + + @Override + public int hashCode() { + return Objects.hash(this.skyflowId, this.data, this.tokens, this.tableName); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional skyflowId = Optional.empty(); + + private Optional> data = Optional.empty(); + + private Optional> tokens = Optional.empty(); + + private Optional tableName = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1UpdateRecordData other) { + skyflowId(other.getSkyflowId()); + data(other.getData()); + tokens(other.getTokens()); + tableName(other.getTableName()); + return this; + } + + /** + *

Skyflow ID for the record to be updated

+ */ + @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) + public Builder skyflowId(Optional skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + public Builder skyflowId(String skyflowId) { + this.skyflowId = Optional.ofNullable(skyflowId); + return this; + } + + /** + *

List of data row wise that is to be updated in the vault

+ */ + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Optional> data) { + this.data = data; + return this; + } + + public Builder data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + /** + *

undocumented_field; Tokens data for the columns if any

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + public Builder tokens(Map tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + /** + *

Table name for the record

+ */ + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public Builder tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + public Builder tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + public V1UpdateRecordData build() { + return new V1UpdateRecordData(skyflowId, data, tokens, tableName, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateResponse.java new file mode 100644 index 00000000..38dfe0ab --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateResponse.java @@ -0,0 +1,93 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1UpdateResponse.Builder.class) +public final class V1UpdateResponse { + private final Optional> records; + + private final Map additionalProperties; + + private V1UpdateResponse(Optional> records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of updated records with skyflow ID, tokens, data, and any partial errors + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1UpdateResponse && equalTo((V1UpdateResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1UpdateResponse other) { + return records.equals(other.records); + } + + @Override + public int hashCode() { + return Objects.hash(this.records); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> records = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1UpdateResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of updated records with skyflow ID, tokens, data, and any partial errors

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + public V1UpdateResponse build() { + return new V1UpdateResponse(records, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1Upsert.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1Upsert.java new file mode 100644 index 00000000..a0c27b0e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1Upsert.java @@ -0,0 +1,118 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.*; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1Upsert.Builder.class) +public final class V1Upsert { + private final Optional updateType; + + private final Optional> uniqueColumns; + + private final Map additionalProperties; + + private V1Upsert( + Optional updateType, + Optional> uniqueColumns, + Map additionalProperties) { + this.updateType = updateType; + this.uniqueColumns = uniqueColumns; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("updateType") + public Optional getUpdateType() { + return updateType; + } + + /** + * @return Name of a unique columns in the table. Uses upsert operations to check if a record exists based on the unique column's value. If a matching record exists, the record updates with the values you provide. If a matching record doesn't exist, the upsert operation inserts a new record. + */ + @JsonProperty("uniqueColumns") + public Optional> getUniqueColumns() { + return uniqueColumns; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1Upsert && equalTo((V1Upsert) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1Upsert other) { + return updateType.equals(other.updateType) && uniqueColumns.equals(other.uniqueColumns); + } + + @Override + public int hashCode() { + return Objects.hash(this.updateType, this.uniqueColumns); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional updateType = Optional.empty(); + + private Optional> uniqueColumns = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1Upsert other) { + updateType(other.getUpdateType()); + uniqueColumns(other.getUniqueColumns()); + return this; + } + + @JsonSetter(value = "updateType", nulls = Nulls.SKIP) + public Builder updateType(Optional updateType) { + this.updateType = updateType; + return this; + } + + public Builder updateType(FlowEnumUpdateType updateType) { + this.updateType = Optional.ofNullable(updateType); + return this; + } + + /** + *

Name of a unique columns in the table. Uses upsert operations to check if a record exists based on the unique column's value. If a matching record exists, the record updates with the values you provide. If a matching record doesn't exist, the upsert operation inserts a new record.

+ */ + @JsonSetter(value = "uniqueColumns", nulls = Nulls.SKIP) + public Builder uniqueColumns(Optional> uniqueColumns) { + this.uniqueColumns = uniqueColumns; + return this; + } + + public Builder uniqueColumns(List uniqueColumns) { + this.uniqueColumns = Optional.ofNullable(uniqueColumns); + return this; + } + + public V1Upsert build() { + return new V1Upsert(updateType, uniqueColumns, additionalProperties); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/utils/Constants.java b/flowvault/src/main/java/com/skyflow/utils/Constants.java new file mode 100644 index 00000000..ff5f9eb2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/utils/Constants.java @@ -0,0 +1,49 @@ +package com.skyflow.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public final class Constants extends BaseConstants { + public static final String SDK_NAME = "Skyflow Java SDK "; + public static final String SDK_VERSION; + public static final String VAULT_DOMAIN = ".skyvault."; + public static final String SDK_PREFIX; + public static final Integer INSERT_BATCH_SIZE = 50; + public static final Integer MAX_INSERT_BATCH_SIZE = 1000; + public static final Integer INSERT_CONCURRENCY_LIMIT = 1; + public static final Integer MAX_INSERT_CONCURRENCY_LIMIT = 10; + public static final Integer DETOKENIZE_BATCH_SIZE = 50; + public static final Integer DETOKENIZE_CONCURRENCY_LIMIT = 1; + public static final Integer MAX_DETOKENIZE_BATCH_SIZE = 1000; + public static final Integer MAX_DETOKENIZE_CONCURRENCY_LIMIT = 10; + public static final Integer DELETE_TOKENS_BATCH_SIZE = 50; + public static final Integer DELETE_TOKENS_CONCURRENCY_LIMIT = 1; + public static final Integer MAX_DELETE_TOKENS_BATCH_SIZE = 1000; + public static final Integer MAX_DELETE_TOKENS_CONCURRENCY_LIMIT = 10; + public static final Integer TOKENIZE_BATCH_SIZE = 50; + public static final Integer TOKENIZE_CONCURRENCY_LIMIT = 1; + public static final Integer MAX_TOKENIZE_BATCH_SIZE = 1000; + public static final Integer MAX_TOKENIZE_CONCURRENCY_LIMIT = 10; + public static final String DEFAULT_SDK_VERSION = "v3"; + public static final String CONTEXT_KEY_REGEX = "^[a-zA-Z0-9_]+$"; + + static { + String sdkVersion; + // Use a static initializer block to read the properties file + Properties properties = new Properties(); + try (InputStream input = Constants.class.getClassLoader().getResourceAsStream("sdk.properties")) { + if (input == null) { + sdkVersion = DEFAULT_SDK_VERSION; + } else { + properties.load(input); + sdkVersion = properties.getProperty("sdk.version", DEFAULT_SDK_VERSION); + } + } catch (IOException ex) { + sdkVersion = DEFAULT_SDK_VERSION; + } + SDK_VERSION = sdkVersion; + SDK_PREFIX = SDK_NAME + " " + SDK_VERSION; + } + +} diff --git a/flowvault/src/main/java/com/skyflow/utils/Utils.java b/flowvault/src/main/java/com/skyflow/utils/Utils.java new file mode 100644 index 00000000..207edae6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/utils/Utils.java @@ -0,0 +1,111 @@ +package com.skyflow.utils; + +import com.google.gson.JsonObject; +import com.skyflow.config.Credentials; +import com.skyflow.enums.Env; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; +import com.skyflow.generated.rest.types.V1InsertRecordData; +import com.skyflow.generated.rest.types.V1InsertResponse; +import com.skyflow.generated.rest.types.V1RecordResponseObject; +import com.skyflow.generated.rest.types.V1TokenGroupRedactions; +import com.skyflow.logs.ErrorLogs; +import com.skyflow.logs.InfoLogs; +import com.skyflow.serviceaccount.util.BearerToken; +import com.skyflow.serviceaccount.util.Token; +import com.skyflow.utils.logger.LogUtil; +import com.skyflow.vault.data.*; +import io.github.cdimascio.dotenv.Dotenv; +import io.github.cdimascio.dotenv.DotenvException; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class Utils extends BaseUtils { + + public static String getVaultURL(String clusterId, Env env) { + return getVaultURL(clusterId, env, Constants.VAULT_DOMAIN); + } + + public static JsonObject getMetrics() { + JsonObject details = getCommonMetrics(); + String sdkVersion = Constants.SDK_VERSION; + details.addProperty(Constants.SDK_METRIC_NAME_VERSION, Constants.SDK_METRIC_NAME_VERSION_PREFIX + sdkVersion); + return details; + } + + + public static String getEnvVaultURL() throws SkyflowException { + try { + String vaultURL = System.getenv("VAULT_URL"); + if (vaultURL == null) { + Dotenv dotenv = Dotenv.load(); + vaultURL = dotenv.get("VAULT_URL"); + } + if (vaultURL != null && vaultURL.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_VAULT_URL.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyVaultUrl.getMessage()); + } else if (vaultURL != null && !isValidURL(vaultURL)) { + LogUtil.printErrorLog(ErrorLogs.INVALID_VAULT_URL_FORMAT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidVaultUrlFormat.getMessage()); + } + return vaultURL; + } catch (DotenvException e) { + return null; + } + } + + public static boolean isValidURL(String url) { + URL parsedUrl; + try { + parsedUrl = new URL(url); + } catch (MalformedURLException e) { + return false; + } + + if (!parsedUrl.getProtocol().equalsIgnoreCase("https")) { + return false; + } else { + return parsedUrl.getHost() != null && !parsedUrl.getHost().isEmpty(); + } + } + + + public static String generateBearerToken(Credentials credentials) throws SkyflowException { + if (credentials.getPath() != null) { + BearerToken.BearerTokenBuilder builder = BearerToken.builder() + .setCredentials(new File(credentials.getPath())) + .setRoles(credentials.getRoles()); + Object ctx = credentials.getContext(); + if (ctx instanceof String) { + builder.setCtx((String) ctx); + } else if (ctx instanceof Map) { + builder.setCtx((Map) ctx); + } + return builder.build().getBearerToken(); + } else if (credentials.getCredentialsString() != null) { + BearerToken.BearerTokenBuilder builder = BearerToken.builder() + .setCredentials(credentials.getCredentialsString()) + .setRoles(credentials.getRoles()); + Object ctx = credentials.getContext(); + if (ctx instanceof String) { + builder.setCtx((String) ctx); + } else if (ctx instanceof Map) { + builder.setCtx((Map) ctx); + } + return builder.build().getBearerToken(); + } else { + return credentials.getToken(); + } + } + + +} diff --git a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java new file mode 100644 index 00000000..06995825 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java @@ -0,0 +1,150 @@ +package com.skyflow.utils.validations; + +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; +import com.skyflow.utils.Constants; +import com.skyflow.utils.Utils; +import com.skyflow.utils.logger.LogUtil; + +import java.util.ArrayList; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Validations extends BaseValidations { + private Validations() { + super(); + } + + public static void validateCredentials(Credentials credentials) throws SkyflowException { + int nonNullMembers = 0; + String path = credentials.getPath(); + String credentialsString = credentials.getCredentialsString(); + String token = credentials.getToken(); + String apiKey = credentials.getApiKey(); + Object context = credentials.getContext(); + ArrayList roles = credentials.getRoles(); + + if (path != null) nonNullMembers++; + if (credentialsString != null) nonNullMembers++; + if (token != null) nonNullMembers++; + if (apiKey != null) nonNullMembers++; + + if (nonNullMembers > 1) { + LogUtil.printErrorLog(ErrorLogs.MULTIPLE_TOKEN_GENERATION_MEANS_PASSED.getLog()); + throw new SkyflowException( + ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MultipleTokenGenerationMeansPassed.getMessage() + ); + } else if (nonNullMembers < 1) { + LogUtil.printErrorLog(ErrorLogs.NO_TOKEN_GENERATION_MEANS_PASSED.getLog()); + throw new SkyflowException( + ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NoTokenGenerationMeansPassed.getMessage() + ); + } else if (path != null && path.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_PATH.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialFilePath.getMessage()); + } else if (credentialsString != null && credentialsString.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_STRING.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialsString.getMessage()); + } else if (token != null && token.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_TOKEN_VALUE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyToken.getMessage()); + } else if (apiKey != null) { + if (apiKey.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_API_KEY_VALUE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyApikey.getMessage()); + } else { + Pattern pattern = Pattern.compile(Constants.API_KEY_REGEX); + Matcher matcher = pattern.matcher(apiKey); + if (!matcher.matches()) { + LogUtil.printErrorLog(ErrorLogs.INVALID_API_KEY.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidApikey.getMessage()); + } + } + } else if (roles != null) { + if (roles.isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_ROLES.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoles.getMessage()); + } else { + for (int index = 0; index < roles.size(); index++) { + String role = roles.get(index); + if (role == null || role.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_ROLE_IN_ROLES.getLog(), Integer.toString(index) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoleInRoles.getMessage()); + } + } + } + } + if (context != null) { + if (context instanceof String) { + String ctxStr = (String) context; + if (ctxStr.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); + } + } else if (context instanceof Map) { + Map ctxMap = (Map) context; + if (ctxMap.isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); + } + Pattern ctxKeyPattern = Pattern.compile(Constants.CONTEXT_KEY_REGEX); + for (Object key : ctxMap.keySet()) { + if (key == null || !ctxKeyPattern.matcher(key.toString()).matches()) { + String keyStr = key == null ? "null" : key.toString(); + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_CONTEXT_MAP_KEY.getLog(), keyStr)); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), + Utils.parameterizedString(ErrorMessage.InvalidContextMapKey.getMessage(), keyStr)); + } + } + } else { + LogUtil.printErrorLog(ErrorLogs.INVALID_CONTEXT_TYPE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidContextType.getMessage()); + } + } + } + + + public static void validateVaultConfiguration(VaultConfig vaultConfig) throws SkyflowException { + String vaultId = vaultConfig.getVaultId(); + String clusterId = vaultConfig.getClusterId(); + String vaultURL = vaultConfig.getVaultURL(); + Credentials credentials = vaultConfig.getCredentials(); + + if (vaultId == null) { + LogUtil.printErrorLog(ErrorLogs.VAULT_ID_IS_REQUIRED.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidVaultId.getMessage()); + } else if (vaultId.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_VAULT_ID.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyVaultId.getMessage()); + } else if (credentials != null) { + validateCredentials(credentials); + } + + if (vaultURL != null) { + if (vaultURL.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_VAULT_URL.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyVaultUrl.getMessage()); + } else if (!Utils.isValidURL(vaultURL)) { + LogUtil.printErrorLog(ErrorLogs.INVALID_VAULT_URL_FORMAT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidVaultUrlFormat.getMessage()); + } + } else if (Utils.getEnvVaultURL() == null) { + if (clusterId == null) { + LogUtil.printErrorLog(ErrorLogs.EITHER_VAULT_URL_OR_CLUSTER_ID_REQUIRED.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EitherVaultUrlOrClusterIdRequired.getMessage()); + } else if (clusterId.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_CLUSTER_ID.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyClusterId.getMessage()); + } + } + } + +} diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java new file mode 100644 index 00000000..62f8f2cb --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -0,0 +1,34 @@ +package com.skyflow.vault.controller; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.skyflow.VaultClient; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.errors.SkyflowException; +import com.skyflow.utils.Utils; +import com.skyflow.vault.data.DetokenizeRequest; +import com.skyflow.vault.data.DetokenizeResponse; +import com.skyflow.vault.data.InsertRequest; +import com.skyflow.vault.data.InsertResponse; + +public final class VaultController extends VaultClient implements IVaultController{ + private static final Gson gson = new GsonBuilder().serializeNulls().create(); + private JsonObject metrics = Utils.getMetrics(); + + public VaultController(VaultConfig vaultConfig, Credentials credentials) throws SkyflowException { + super(vaultConfig, credentials); + } + + + @Override + public InsertResponse insert(InsertRequest request) throws SkyflowException { + return null; + } + + @Override + public DetokenizeResponse detokenize(DetokenizeRequest request) throws SkyflowException { + return null; + } +} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java new file mode 100644 index 00000000..0cd8b159 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class DetokenizeRequest extends BaseDetokenizeRequest{ +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java new file mode 100644 index 00000000..91dbe710 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class DetokenizeResponse extends BaseDetokenizeResponse{ +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java new file mode 100644 index 00000000..b3c82df0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class InsertRequest extends BaseInsertRequest{ +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java new file mode 100644 index 00000000..2d7e6e32 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class InsertResponse extends BaseInsertResponse{ +} diff --git a/pom.xml b/pom.xml index 585350f7..1066c387 100644 --- a/pom.xml +++ b/pom.xml @@ -5,9 +5,9 @@ 4.0.0 com.skyflow - skyflow-java - 2.1.0 - jar + skyflow + 1.0.0 + pom ${project.groupId}:${project.artifactId} Skyflow SDK for the Java programming language @@ -25,6 +25,11 @@ skyflow + + common + v2 + flowvault + scm:git:git://github.com:skyflowapi/skyflow-java.git scm:git:ssh://github.com:skyflowapi/skyflow-java.git @@ -32,6 +37,7 @@ + true 8 8 4.12.0 @@ -42,14 +48,13 @@ 4.13.2 2.3.1 1.3.5 - ${project.version} com.fasterxml.jackson.core jackson-databind - 2.18.6 + 2.17.2 compile @@ -124,7 +129,6 @@ 4.13.2 test - org.powermock powermock-module-junit4 @@ -140,12 +144,6 @@ - - - src/main/resources - true - - org.apache.maven.plugins @@ -166,7 +164,8 @@ 3.2.0 - com.skyflow.generated.rest.* + com.skyflow.generated.rest.*: + com.skyflow.generated.auth.*: @@ -175,50 +174,14 @@ jar + org.apache.maven.plugins maven-surefire-plugin - 3.2.5 - - false - - @{argLine} - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.net=ALL-UNNAMED - --add-opens java.base/java.util=ALL-UNNAMED - --add-opens java.base/java.io=ALL-UNNAMED - --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED - - - **/*Test.java - **/*Tests.java - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.3.1 - - checkstyle.xml - - false - true - - **/generated/** - - - - validate - validate - - check - - - + 2.22.2 org.jacoco @@ -290,50 +253,4 @@ https://repo.maven.apache.org/maven2/ - - - - maven-central - - - central - https://central.sonatype.com/api/v1/publisher/upload - - - central-snapshots - https://central.sonatype.com/api/v1/publisher/upload - - - - - - org.sonatype.central - central-publishing-maven-plugin - 0.4.0 - true - - central - true - true - - - - - - - jfrog - - - central - prekarilabs.jfrog.io-releases - https://prekarilabs.jfrog.io/artifactory/skyflow-java - - - snapshots - prekarilabs.jfrog.io-snapshots - https://prekarilabs.jfrog.io/artifactory/skyflow-java - - - - - + \ No newline at end of file diff --git a/v2/pom.xml b/v2/pom.xml new file mode 100644 index 00000000..cf5a35b6 --- /dev/null +++ b/v2/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + com.skyflow + skyflow + 1.0.0 + ../pom.xml + + + skyflow-java + 2.1.1 + com.skyflow + + + 8 + 8 + UTF-8 + + + + + com.skyflow + common + 1.0.0 + + + + \ No newline at end of file diff --git a/src/main/java/com/skyflow/ConnectionClient.java b/v2/src/main/java/com/skyflow/ConnectionClient.java similarity index 100% rename from src/main/java/com/skyflow/ConnectionClient.java rename to v2/src/main/java/com/skyflow/ConnectionClient.java diff --git a/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java similarity index 96% rename from src/main/java/com/skyflow/Skyflow.java rename to v2/src/main/java/com/skyflow/Skyflow.java index eba8d6fd..3889b0bf 100644 --- a/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -19,12 +19,12 @@ import java.util.LinkedHashMap; -public final class Skyflow { +public final class Skyflow extends BaseSkyflow { private final SkyflowClientBuilder builder; private Skyflow(SkyflowClientBuilder builder) { + super(builder); this.builder = builder; - LogUtil.printInfoLog(InfoLogs.CLIENT_INITIALIZED.getLog()); } public static SkyflowClientBuilder builder() { @@ -50,6 +50,16 @@ public Skyflow removeVaultConfig(String vaultId) throws SkyflowException { return this; } + public Skyflow updateSkyflowCredentials(Credentials credentials) throws SkyflowException { + this.builder.addSkyflowCredentials(credentials); + return this; + } + + public Skyflow setLogLevel(LogLevel logLevel) { + this.builder.setLogLevel(logLevel); + return this; + } + public Skyflow addConnectionConfig(ConnectionConfig connectionConfig) throws SkyflowException { this.builder.addConnectionConfig(connectionConfig); return this; @@ -69,15 +79,6 @@ public Skyflow removeConnectionConfig(String connectionId) throws SkyflowExcepti return this; } - public Skyflow updateSkyflowCredentials(Credentials credentials) throws SkyflowException { - this.builder.addSkyflowCredentials(credentials); - return this; - } - - public Skyflow setLogLevel(LogLevel logLevel) { - this.builder.setLogLevel(logLevel); - return this; - } /** @deprecated Use {@link #setLogLevel(LogLevel)} instead. */ @Deprecated(since = "2.1", forRemoval = true) @@ -86,10 +87,6 @@ public Skyflow updateLogLevel(LogLevel logLevel) { return setLogLevel(logLevel); } - public LogLevel getLogLevel() { - return this.builder.logLevel; - } - public VaultController vault() throws SkyflowException { Object[] array = this.builder.vaultClientsMap.keySet().toArray(); if (array.length < 1) { @@ -148,15 +145,13 @@ public DetectController detect(String vaultId) throws SkyflowException { return controller; } - public static final class SkyflowClientBuilder { + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { private final LinkedHashMap connectionsMap; private final LinkedHashMap vaultClientsMap; private final LinkedHashMap detectClientsMap; private final LinkedHashMap vaultConfigMap; private final LinkedHashMap connectionConfigMap; private Credentials skyflowCredentials; - private LogLevel logLevel; - public SkyflowClientBuilder() { this.vaultClientsMap = new LinkedHashMap<>(); this.detectClientsMap = new LinkedHashMap<>(); @@ -164,7 +159,6 @@ public SkyflowClientBuilder() { this.connectionsMap = new LinkedHashMap<>(); this.connectionConfigMap = new LinkedHashMap<>(); this.skyflowCredentials = null; - this.logLevel = LogLevel.ERROR; } public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { @@ -278,12 +272,9 @@ public SkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throw return this; } + @Override public SkyflowClientBuilder setLogLevel(LogLevel logLevel) { - this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel; - LogUtil.setupLogger(this.logLevel); - LogUtil.printInfoLog(Utils.parameterizedString( - InfoLogs.CURRENT_LOG_LEVEL.getLog(), String.valueOf(logLevel) - )); + super.setLogLevel(logLevel); return this; } @@ -311,4 +302,4 @@ private ConnectionConfig findAndUpdateConnectionConfig(ConnectionConfig connecti return previousConfig; } } -} +} \ No newline at end of file diff --git a/src/main/java/com/skyflow/VaultClient.java b/v2/src/main/java/com/skyflow/VaultClient.java similarity index 92% rename from src/main/java/com/skyflow/VaultClient.java rename to v2/src/main/java/com/skyflow/VaultClient.java index 1d5e5d74..ff8088eb 100644 --- a/src/main/java/com/skyflow/VaultClient.java +++ b/v2/src/main/java/com/skyflow/VaultClient.java @@ -26,12 +26,7 @@ import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.Transformations; import com.skyflow.generated.rest.types.*; -import com.skyflow.logs.InfoLogs; -import com.skyflow.serviceaccount.util.Token; -import com.skyflow.utils.Constants; import com.skyflow.utils.Utils; -import com.skyflow.utils.logger.LogUtil; -import com.skyflow.utils.validations.Validations; import com.skyflow.vault.data.FileUploadRequest; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.UpdateRequest; @@ -41,33 +36,20 @@ import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; import com.skyflow.vault.tokens.TokenizeRequest; -import io.github.cdimascio.dotenv.Dotenv; -import io.github.cdimascio.dotenv.DotenvException; -import okhttp3.ConnectionPool; -import okhttp3.OkHttpClient; -import okhttp3.Request; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.*; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -public class VaultClient { +public class VaultClient extends BaseVaultClient { private final VaultConfig vaultConfig; private final ApiClientBuilder apiClientBuilder; private ApiClient apiClient; - private OkHttpClient sharedHttpClient; - private String currentVaultURL; - private Credentials commonCredentials; - private Credentials finalCredentials; - private String token; - private String apiKey; protected VaultClient(VaultConfig vaultConfig, Credentials credentials) { - super(); this.vaultConfig = vaultConfig; this.commonCredentials = credentials; this.apiClientBuilder = new ApiClientBuilder(); @@ -101,12 +83,12 @@ protected VaultConfig getVaultConfig() { protected void setCommonCredentials(Credentials commonCredentials) throws SkyflowException { this.commonCredentials = commonCredentials; - prioritiseCredentials(); + super.prioritiseCredentials(this.vaultConfig.getCredentials()); } protected void updateVaultConfig() throws SkyflowException { updateVaultURL(); - prioritiseCredentials(); + super.prioritiseCredentials(this.vaultConfig.getCredentials()); } protected V1DetokenizePayload getDetokenizePayload(DetokenizeRequest request) { @@ -233,19 +215,7 @@ protected File getFileForFileUpload(FileUploadRequest fileUploadRequest) throws } protected void setBearerToken() throws SkyflowException { - prioritiseCredentials(); - Validations.validateCredentials(this.finalCredentials); - if (this.finalCredentials.getApiKey() != null) { - LogUtil.printInfoLog(InfoLogs.REUSE_API_KEY.getLog()); - token = this.finalCredentials.getApiKey(); - } else if (token == null || token.trim().isEmpty()) { - token = Utils.generateBearerToken(this.finalCredentials); - } else if (Token.isExpired(token)) { - LogUtil.printInfoLog(InfoLogs.BEARER_TOKEN_EXPIRED.getLog()); - token = Utils.generateBearerToken(this.finalCredentials); - } else { - LogUtil.printInfoLog(InfoLogs.REUSE_BEARER_TOKEN.getLog()); - } + super.setBearerToken(this.vaultConfig.getCredentials()); if (apiClient == null) { updateExecutorInHTTP(); this.apiClient = this.apiClientBuilder.build(); @@ -838,48 +808,9 @@ private void updateVaultURL() { private void updateExecutorInHTTP() { if (sharedHttpClient == null) { - sharedHttpClient = new OkHttpClient.Builder() - .connectionPool(new ConnectionPool(10, 1, TimeUnit.MINUTES)) - .addInterceptor(chain -> { - Request requestWithAuth = chain.request().newBuilder() - .header("Authorization", "Bearer " + this.token) - .build(); - return chain.proceed(requestWithAuth); - }) - .build(); + sharedHttpClient = buildSharedHttpClient(() -> this.token); apiClientBuilder.httpClient(sharedHttpClient); } } - private void prioritiseCredentials() throws SkyflowException { - try { - Credentials original = this.finalCredentials; - if (this.vaultConfig.getCredentials() != null) { - this.finalCredentials = this.vaultConfig.getCredentials(); - } else if (this.commonCredentials != null) { - this.finalCredentials = this.commonCredentials; - } else { - Dotenv dotenv = Dotenv.load(); - String sysCredentials = dotenv.get(Constants.ENV_CREDENTIALS_KEY_NAME); - if (sysCredentials == null) { - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), - ErrorMessage.EmptyCredentials.getMessage()); - } else { - this.finalCredentials = new Credentials(); - this.finalCredentials.setCredentialsString(sysCredentials); - } - } - if (original != null && !original.equals(this.finalCredentials)) { - token = null; - apiKey = null; - } - } catch (DotenvException e) { - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), - ErrorMessage.EmptyCredentials.getMessage()); - } catch (SkyflowException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); - } - } -} +} \ No newline at end of file diff --git a/src/main/java/com/skyflow/config/ConnectionConfig.java b/v2/src/main/java/com/skyflow/config/ConnectionConfig.java similarity index 100% rename from src/main/java/com/skyflow/config/ConnectionConfig.java rename to v2/src/main/java/com/skyflow/config/ConnectionConfig.java diff --git a/v2/src/main/java/com/skyflow/config/Credentials.java b/v2/src/main/java/com/skyflow/config/Credentials.java new file mode 100644 index 00000000..5d1a7859 --- /dev/null +++ b/v2/src/main/java/com/skyflow/config/Credentials.java @@ -0,0 +1,10 @@ +package com.skyflow.config; + +import java.util.Map; + +public class Credentials extends BaseCredentials { + + public Credentials() { + super(); + } +} diff --git a/src/main/java/com/skyflow/config/ManagementConfig.java b/v2/src/main/java/com/skyflow/config/ManagementConfig.java similarity index 100% rename from src/main/java/com/skyflow/config/ManagementConfig.java rename to v2/src/main/java/com/skyflow/config/ManagementConfig.java diff --git a/v2/src/main/java/com/skyflow/config/VaultConfig.java b/v2/src/main/java/com/skyflow/config/VaultConfig.java new file mode 100644 index 00000000..36d86668 --- /dev/null +++ b/v2/src/main/java/com/skyflow/config/VaultConfig.java @@ -0,0 +1,16 @@ +package com.skyflow.config; + +public class VaultConfig extends BaseVaultConfig { + Credentials credentials; + public VaultConfig() { + super(); + } + + public Credentials getCredentials() { + return credentials; + } + + public void setCredentials(Credentials credentials) { + this.credentials = credentials; + } +} diff --git a/src/main/java/com/skyflow/enums/DeidentifyFileStatus.java b/v2/src/main/java/com/skyflow/enums/DeidentifyFileStatus.java similarity index 100% rename from src/main/java/com/skyflow/enums/DeidentifyFileStatus.java rename to v2/src/main/java/com/skyflow/enums/DeidentifyFileStatus.java diff --git a/src/main/java/com/skyflow/enums/DetectEntities.java b/v2/src/main/java/com/skyflow/enums/DetectEntities.java similarity index 100% rename from src/main/java/com/skyflow/enums/DetectEntities.java rename to v2/src/main/java/com/skyflow/enums/DetectEntities.java diff --git a/src/main/java/com/skyflow/enums/DetectOutputTranscriptions.java b/v2/src/main/java/com/skyflow/enums/DetectOutputTranscriptions.java similarity index 100% rename from src/main/java/com/skyflow/enums/DetectOutputTranscriptions.java rename to v2/src/main/java/com/skyflow/enums/DetectOutputTranscriptions.java diff --git a/v2/src/main/java/com/skyflow/enums/Env.java b/v2/src/main/java/com/skyflow/enums/Env.java new file mode 100644 index 00000000..3d1466e9 --- /dev/null +++ b/v2/src/main/java/com/skyflow/enums/Env.java @@ -0,0 +1,8 @@ +package com.skyflow.enums; + +public enum Env { + DEV, + STAGE, + SANDBOX, + PROD +} diff --git a/v2/src/main/java/com/skyflow/enums/InterfaceName.java b/v2/src/main/java/com/skyflow/enums/InterfaceName.java new file mode 100644 index 00000000..98992f21 --- /dev/null +++ b/v2/src/main/java/com/skyflow/enums/InterfaceName.java @@ -0,0 +1,24 @@ +package com.skyflow.enums; + +public enum InterfaceName { + INSERT("insert"), + DETOKENIZE("detokenize"), + GET("get"), + UPDATE("update"), + DELETE("delete"), + QUERY("query"), + TOKENIZE("tokenize"), + FILE_UPLOAD("file upload"), + DETECT("detect"), + INVOKE_CONNECTION("invoke connection"); + + private final String interfaceName; + + InterfaceName(String interfaceName) { + this.interfaceName = interfaceName; + } + + public String getName() { + return interfaceName; + } +} diff --git a/v2/src/main/java/com/skyflow/enums/LogLevel.java b/v2/src/main/java/com/skyflow/enums/LogLevel.java new file mode 100644 index 00000000..a605b520 --- /dev/null +++ b/v2/src/main/java/com/skyflow/enums/LogLevel.java @@ -0,0 +1,9 @@ +package com.skyflow.enums; + +public enum LogLevel { + OFF, + ERROR, + WARN, + INFO, + DEBUG +} diff --git a/src/main/java/com/skyflow/enums/MaskingMethod.java b/v2/src/main/java/com/skyflow/enums/MaskingMethod.java similarity index 100% rename from src/main/java/com/skyflow/enums/MaskingMethod.java rename to v2/src/main/java/com/skyflow/enums/MaskingMethod.java diff --git a/src/main/java/com/skyflow/enums/RedactionType.java b/v2/src/main/java/com/skyflow/enums/RedactionType.java similarity index 100% rename from src/main/java/com/skyflow/enums/RedactionType.java rename to v2/src/main/java/com/skyflow/enums/RedactionType.java diff --git a/src/main/java/com/skyflow/enums/RequestMethod.java b/v2/src/main/java/com/skyflow/enums/RequestMethod.java similarity index 100% rename from src/main/java/com/skyflow/enums/RequestMethod.java rename to v2/src/main/java/com/skyflow/enums/RequestMethod.java diff --git a/src/main/java/com/skyflow/enums/TokenMode.java b/v2/src/main/java/com/skyflow/enums/TokenMode.java similarity index 100% rename from src/main/java/com/skyflow/enums/TokenMode.java rename to v2/src/main/java/com/skyflow/enums/TokenMode.java diff --git a/src/main/java/com/skyflow/enums/TokenType.java b/v2/src/main/java/com/skyflow/enums/TokenType.java similarity index 100% rename from src/main/java/com/skyflow/enums/TokenType.java rename to v2/src/main/java/com/skyflow/enums/TokenType.java diff --git a/v2/src/main/java/com/skyflow/errors/ErrorCode.java b/v2/src/main/java/com/skyflow/errors/ErrorCode.java new file mode 100644 index 00000000..943913c6 --- /dev/null +++ b/v2/src/main/java/com/skyflow/errors/ErrorCode.java @@ -0,0 +1,18 @@ +package com.skyflow.errors; + +public enum ErrorCode { + INVALID_INPUT(400), + INVALID_INDEX(404), + SERVER_ERROR(500), + PARTIAL_SUCCESS(500); + + private final int code; + + ErrorCode(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/src/main/java/com/skyflow/errors/ErrorMessage.java b/v2/src/main/java/com/skyflow/errors/ErrorMessage.java similarity index 100% rename from src/main/java/com/skyflow/errors/ErrorMessage.java rename to v2/src/main/java/com/skyflow/errors/ErrorMessage.java diff --git a/v2/src/main/java/com/skyflow/errors/HttpStatus.java b/v2/src/main/java/com/skyflow/errors/HttpStatus.java new file mode 100644 index 00000000..2cdadbb0 --- /dev/null +++ b/v2/src/main/java/com/skyflow/errors/HttpStatus.java @@ -0,0 +1,15 @@ +package com.skyflow.errors; + +public enum HttpStatus { + BAD_REQUEST("Bad Request"); + + private final String httpStatus; + + HttpStatus(String httpStatus) { + this.httpStatus = httpStatus; + } + + public String getHttpStatus() { + return httpStatus; + } +} diff --git a/src/main/java/com/skyflow/errors/SkyflowException.java b/v2/src/main/java/com/skyflow/errors/SkyflowException.java similarity index 100% rename from src/main/java/com/skyflow/errors/SkyflowException.java rename to v2/src/main/java/com/skyflow/errors/SkyflowException.java diff --git a/src/main/java/com/skyflow/generated/rest/ApiClient.java b/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java similarity index 98% rename from src/main/java/com/skyflow/generated/rest/ApiClient.java rename to v2/src/main/java/com/skyflow/generated/rest/ApiClient.java index 1eb1e429..eb4c2020 100644 --- a/src/main/java/com/skyflow/generated/rest/ApiClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java @@ -3,6 +3,7 @@ */ package com.skyflow.generated.rest; +import com.skyflow.generated.rest.ApiClientBuilder; import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.Suppliers; import com.skyflow.generated.rest.resources.audit.AuditClient; @@ -14,6 +15,7 @@ import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.generated.rest.resources.strings.StringsClient; import com.skyflow.generated.rest.resources.tokens.TokensClient; + import java.util.function.Supplier; public class ApiClient { diff --git a/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java b/v2/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java rename to v2/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java diff --git a/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java b/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java similarity index 98% rename from src/main/java/com/skyflow/generated/rest/AsyncApiClient.java rename to v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java index 405d0208..ec3543a3 100644 --- a/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java @@ -3,6 +3,7 @@ */ package com.skyflow.generated.rest; +import com.skyflow.generated.rest.AsyncApiClientBuilder; import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.Suppliers; import com.skyflow.generated.rest.resources.audit.AsyncAuditClient; @@ -14,6 +15,7 @@ import com.skyflow.generated.rest.resources.records.AsyncRecordsClient; import com.skyflow.generated.rest.resources.strings.AsyncStringsClient; import com.skyflow.generated.rest.resources.tokens.AsyncTokensClient; + import java.util.function.Supplier; public class AsyncApiClient { diff --git a/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java b/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java rename to v2/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java b/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java new file mode 100644 index 00000000..be5247eb --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java @@ -0,0 +1,74 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.Response; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This exception type will be thrown for any non-2XX API responses. + */ +public class ApiClientApiException extends ApiClientException { + /** + * The error code of the response that triggered the exception. + */ + private final int statusCode; + + /** + * The body of the response that triggered the exception. + */ + private final Object body; + + private final Map> headers; + + public ApiClientApiException(String message, int statusCode, Object body) { + super(message); + this.statusCode = statusCode; + this.body = body; + this.headers = new HashMap<>(); + } + + public ApiClientApiException(String message, int statusCode, Object body, Response rawResponse) { + super(message); + this.statusCode = statusCode; + this.body = body; + this.headers = new HashMap<>(); + rawResponse.headers().forEach(header -> { + String key = header.component1(); + String value = header.component2(); + this.headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value); + }); + } + + /** + * @return the statusCode + */ + public int statusCode() { + return this.statusCode; + } + + /** + * @return the body + */ + public Object body() { + return this.body; + } + + /** + * @return the headers + */ + public Map> headers() { + return this.headers; + } + + @Override + public String toString() { + return "ApiClientApiException{" + "message: " + getMessage() + ", statusCode: " + statusCode + ", body: " + body + + "}"; + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientException.java b/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientException.java new file mode 100644 index 00000000..7987eba6 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientException.java @@ -0,0 +1,17 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +/** + * This class serves as the base exception for all errors in the SDK. + */ +public class ApiClientException extends RuntimeException { + public ApiClientException(String message) { + super(message); + } + + public ApiClientException(String message, Exception e) { + super(message, e); + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java b/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java new file mode 100644 index 00000000..c743352c --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java @@ -0,0 +1,38 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.Response; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class ApiClientHttpResponse { + + private final T body; + + private final Map> headers; + + public ApiClientHttpResponse(T body, Response rawResponse) { + this.body = body; + + Map> headers = new HashMap<>(); + rawResponse.headers().forEach(header -> { + String key = header.component1(); + String value = header.component2(); + headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value); + }); + this.headers = headers; + } + + public T body() { + return this.body; + } + + public Map> headers() { + return headers; + } +} diff --git a/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java b/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/core/ClientOptions.java rename to v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java index ddb0e107..da41fb25 100644 --- a/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java @@ -3,12 +3,13 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.OkHttpClient; + import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -import okhttp3.OkHttpClient; public final class ClientOptions { private final Environment environment; diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java b/v2/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java new file mode 100644 index 00000000..a0a6d7c4 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java @@ -0,0 +1,56 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; + +/** + * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects. + */ +class DateTimeDeserializer extends JsonDeserializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule().addDeserializer(OffsetDateTime.class, new DateTimeDeserializer()); + } + + /** + * Gets a module wrapping this deserializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + JsonToken token = parser.currentToken(); + if (token == JsonToken.VALUE_NUMBER_INT) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC); + } else { + TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( + parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from); + + if (temporal.query(TemporalQueries.offset()) == null) { + return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC); + } else { + return OffsetDateTime.from(temporal); + } + } + } +} diff --git a/src/main/java/com/skyflow/generated/rest/core/Environment.java b/v2/src/main/java/com/skyflow/generated/rest/core/Environment.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/Environment.java rename to v2/src/main/java/com/skyflow/generated/rest/core/Environment.java diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java b/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java new file mode 100644 index 00000000..c27d39a0 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java @@ -0,0 +1,62 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.skyflow.generated.rest.core.InputStreamRequestBody; +import okhttp3.MediaType; +import okhttp3.RequestBody; +import org.jetbrains.annotations.Nullable; + +import java.io.InputStream; +import java.util.Objects; + +/** + * Represents a file stream with associated metadata for file uploads. + */ +public class FileStream { + private final InputStream inputStream; + private final String fileName; + private final MediaType contentType; + + /** + * Constructs a FileStream with the given input stream and optional metadata. + * + * @param inputStream The input stream of the file content. Must not be null. + * @param fileName The name of the file, or null if unknown. + * @param contentType The MIME type of the file content, or null if unknown. + * @throws NullPointerException if inputStream is null + */ + public FileStream(InputStream inputStream, @Nullable String fileName, @Nullable MediaType contentType) { + this.inputStream = Objects.requireNonNull(inputStream, "Input stream cannot be null"); + this.fileName = fileName; + this.contentType = contentType; + } + + public FileStream(InputStream inputStream) { + this(inputStream, null, null); + } + + public InputStream getInputStream() { + return inputStream; + } + + @Nullable + public String getFileName() { + return fileName; + } + + @Nullable + public MediaType getContentType() { + return contentType; + } + + /** + * Creates a RequestBody suitable for use with OkHttp client. + * + * @return A RequestBody instance representing this file stream. + */ + public RequestBody toRequestBody() { + return new InputStreamRequestBody(contentType, inputStream); + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java b/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java new file mode 100644 index 00000000..55c3c971 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java @@ -0,0 +1,80 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okhttp3.internal.Util; +import okio.BufferedSink; +import okio.Okio; +import okio.Source; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; + +/** + * A custom implementation of OkHttp's RequestBody that wraps an InputStream. + * This class allows streaming of data from an InputStream directly to an HTTP request body, + * which is useful for file uploads or sending large amounts of data without loading it all into memory. + */ +public class InputStreamRequestBody extends RequestBody { + private final InputStream inputStream; + private final MediaType contentType; + + /** + * Constructs an InputStreamRequestBody with the specified content type and input stream. + * + * @param contentType the MediaType of the content, or null if not known + * @param inputStream the InputStream containing the data to be sent + * @throws NullPointerException if inputStream is null + */ + public InputStreamRequestBody(@Nullable MediaType contentType, InputStream inputStream) { + this.contentType = contentType; + this.inputStream = Objects.requireNonNull(inputStream, "inputStream == null"); + } + + /** + * Returns the content type of this request body. + * + * @return the MediaType of the content, or null if not specified + */ + @Nullable + @Override + public MediaType contentType() { + return contentType; + } + + /** + * Returns the content length of this request body, if known. + * This method attempts to determine the length using the InputStream's available() method, + * which may not always accurately reflect the total length of the stream. + * + * @return the content length, or -1 if the length is unknown + * @throws IOException if an I/O error occurs + */ + @Override + public long contentLength() throws IOException { + return inputStream.available() == 0 ? -1 : inputStream.available(); + } + + /** + * Writes the content of the InputStream to the given BufferedSink. + * This method is responsible for transferring the data from the InputStream to the network request. + * + * @param sink the BufferedSink to write the content to + * @throws IOException if an I/O error occurs during writing + */ + @Override + public void writeTo(BufferedSink sink) throws IOException { + Source source = null; + try { + source = Okio.source(inputStream); + sink.writeAll(source); + } finally { + Util.closeQuietly(Objects.requireNonNull(source)); + } + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/MediaTypes.java b/v2/src/main/java/com/skyflow/generated/rest/core/MediaTypes.java new file mode 100644 index 00000000..11714cb8 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/MediaTypes.java @@ -0,0 +1,13 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.MediaType; + +public final class MediaTypes { + + public static final MediaType APPLICATION_JSON = MediaType.parse("application/json"); + + private MediaTypes() {} +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/Nullable.java b/v2/src/main/java/com/skyflow/generated/rest/core/Nullable.java new file mode 100644 index 00000000..5929c12d --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/Nullable.java @@ -0,0 +1,140 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.util.Optional; +import java.util.function.Function; + +public final class Nullable { + + private final Either, Null> value; + + private Nullable() { + this.value = Either.left(Optional.empty()); + } + + private Nullable(T value) { + if (value == null) { + this.value = Either.right(Null.INSTANCE); + } else { + this.value = Either.left(Optional.of(value)); + } + } + + public static Nullable ofNull() { + return new Nullable<>(null); + } + + public static Nullable of(T value) { + return new Nullable<>(value); + } + + public static Nullable empty() { + return new Nullable<>(); + } + + public static Nullable ofOptional(Optional value) { + if (value.isPresent()) { + return of(value.get()); + } else { + return empty(); + } + } + + public boolean isNull() { + return this.value.isRight(); + } + + public boolean isEmpty() { + return this.value.isLeft() && !this.value.getLeft().isPresent(); + } + + public T get() { + if (this.isNull()) { + return null; + } + + return this.value.getLeft().get(); + } + + public Nullable map(Function mapper) { + if (this.isNull()) { + return Nullable.ofNull(); + } + + return Nullable.ofOptional(this.value.getLeft().map(mapper)); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Nullable)) { + return false; + } + + if (((Nullable) other).isNull() && this.isNull()) { + return true; + } + + return this.value.getLeft().equals(((Nullable) other).value.getLeft()); + } + + private static final class Either { + private L left = null; + private R right = null; + + private Either(L left, R right) { + if (left != null && right != null) { + throw new IllegalArgumentException("Left and right argument cannot both be non-null."); + } + + if (left == null && right == null) { + throw new IllegalArgumentException("Left and right argument cannot both be null."); + } + + if (left != null) { + this.left = left; + } + + if (right != null) { + this.right = right; + } + } + + public static Either left(L left) { + return new Either<>(left, null); + } + + public static Either right(R right) { + return new Either<>(null, right); + } + + public boolean isLeft() { + return this.left != null; + } + + public boolean isRight() { + return this.right != null; + } + + public L getLeft() { + if (!this.isLeft()) { + throw new IllegalArgumentException("Cannot get left from right Either."); + } + return this.left; + } + + public R getRight() { + if (!this.isRight()) { + throw new IllegalArgumentException("Cannot get right from left Either."); + } + return this.right; + } + } + + private static final class Null { + private static final Null INSTANCE = new Null(); + + private Null() {} + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java b/v2/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java new file mode 100644 index 00000000..98c33be4 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java @@ -0,0 +1,19 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.util.Optional; + +public final class NullableNonemptyFilter { + @Override + public boolean equals(Object o) { + boolean isOptionalEmpty = isOptionalEmpty(o); + + return isOptionalEmpty; + } + + private boolean isOptionalEmpty(Object o) { + return o instanceof Optional && !((Optional) o).isPresent(); + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java b/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java new file mode 100644 index 00000000..3f3a2213 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java @@ -0,0 +1,38 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.skyflow.generated.rest.core.DateTimeDeserializer; + +import java.io.IOException; + +public final class ObjectMappers { + public static final ObjectMapper JSON_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .addModule(new JavaTimeModule()) + .addModule(DateTimeDeserializer.getModule()) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + + private ObjectMappers() {} + + public static String stringify(Object o) { + try { + return JSON_MAPPER + .setSerializationInclusion(JsonInclude.Include.ALWAYS) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(o); + } catch (IOException e) { + return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); + } + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java b/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java new file mode 100644 index 00000000..c0687736 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java @@ -0,0 +1,139 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import okhttp3.HttpUrl; +import okhttp3.MultipartBody; + +import java.util.*; + +public class QueryStringMapper { + + private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER; + + public static void addQueryParameter(HttpUrl.Builder httpUrl, String key, Object value, boolean arraysAsRepeats) { + JsonNode valueNode = MAPPER.valueToTree(value); + + List> flat; + if (valueNode.isObject()) { + flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats); + } else if (valueNode.isArray()) { + flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats); + } else { + if (valueNode.isTextual()) { + httpUrl.addQueryParameter(key, valueNode.textValue()); + } else { + httpUrl.addQueryParameter(key, valueNode.toString()); + } + return; + } + + for (Map.Entry field : flat) { + if (field.getValue().isTextual()) { + httpUrl.addQueryParameter(key + field.getKey(), field.getValue().textValue()); + } else { + httpUrl.addQueryParameter(key + field.getKey(), field.getValue().toString()); + } + } + } + + public static void addFormDataPart( + MultipartBody.Builder multipartBody, String key, Object value, boolean arraysAsRepeats) { + JsonNode valueNode = MAPPER.valueToTree(value); + + List> flat; + if (valueNode.isObject()) { + flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats); + } else if (valueNode.isArray()) { + flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats); + } else { + if (valueNode.isTextual()) { + multipartBody.addFormDataPart(key, valueNode.textValue()); + } else { + multipartBody.addFormDataPart(key, valueNode.toString()); + } + return; + } + + for (Map.Entry field : flat) { + if (field.getValue().isTextual()) { + multipartBody.addFormDataPart( + key + field.getKey(), field.getValue().textValue()); + } else { + multipartBody.addFormDataPart( + key + field.getKey(), field.getValue().toString()); + } + } + } + + public static List> flattenObject(ObjectNode object, boolean arraysAsRepeats) { + List> flat = new ArrayList<>(); + + Iterator> fields = object.fields(); + while (fields.hasNext()) { + Map.Entry field = fields.next(); + + String key = "[" + field.getKey() + "]"; + + if (field.getValue().isObject()) { + List> flatField = + flattenObject((ObjectNode) field.getValue(), arraysAsRepeats); + addAll(flat, flatField, key); + } else if (field.getValue().isArray()) { + List> flatField = + flattenArray((ArrayNode) field.getValue(), key, arraysAsRepeats); + addAll(flat, flatField, ""); + } else { + flat.add(new AbstractMap.SimpleEntry<>(key, field.getValue())); + } + } + + return flat; + } + + private static List> flattenArray( + ArrayNode array, String key, boolean arraysAsRepeats) { + List> flat = new ArrayList<>(); + + Iterator elements = array.elements(); + + int index = 0; + while (elements.hasNext()) { + JsonNode element = elements.next(); + + String indexKey = key + "[" + index + "]"; + + if (arraysAsRepeats) { + indexKey = key; + } + + if (element.isObject()) { + List> flatField = flattenObject((ObjectNode) element, arraysAsRepeats); + addAll(flat, flatField, indexKey); + } else if (element.isArray()) { + List> flatField = flattenArray((ArrayNode) element, "", arraysAsRepeats); + addAll(flat, flatField, indexKey); + } else { + flat.add(new AbstractMap.SimpleEntry<>(indexKey, element)); + } + + index++; + } + + return flat; + } + + private static void addAll( + List> target, List> source, String prefix) { + for (Map.Entry entry : source) { + Map.Entry entryToAdd = + new AbstractMap.SimpleEntry<>(prefix + entry.getKey(), entry.getValue()); + target.add(entryToAdd); + } + } +} diff --git a/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java b/v2/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/core/RequestOptions.java rename to v2/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java new file mode 100644 index 00000000..1bb0b5dc --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java @@ -0,0 +1,46 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.Response; + +import java.io.FilterInputStream; +import java.io.IOException; + +/** + * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the + * OkHttp Response object is properly closed when the stream is closed. + * + * This class extends FilterInputStream and takes an OkHttp Response object as a parameter. + * It retrieves the InputStream from the Response and overrides the close method to close + * both the InputStream and the Response object, ensuring proper resource management and preventing + * premature closure of the underlying HTTP connection. + */ +public class ResponseBodyInputStream extends FilterInputStream { + private final Response response; + + /** + * Constructs a ResponseBodyInputStream that wraps the InputStream from the given OkHttp + * Response object. + * + * @param response the OkHttp Response object from which the InputStream is retrieved + * @throws IOException if an I/O error occurs while retrieving the InputStream + */ + public ResponseBodyInputStream(Response response) throws IOException { + super(response.body().byteStream()); + this.response = response; + } + + /** + * Closes the InputStream and the associated OkHttp Response object. This ensures that the + * underlying HTTP connection is properly closed after the stream is no longer needed. + * + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + super.close(); + response.close(); // Ensure the response is closed when the stream is closed + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java new file mode 100644 index 00000000..e6c1a525 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java @@ -0,0 +1,45 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.Response; + +import java.io.FilterReader; +import java.io.IOException; + +/** + * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the + * OkHttp Response object is properly closed when the reader is closed. + * + * This class extends FilterReader and takes an OkHttp Response object as a parameter. + * It retrieves the Reader from the Response and overrides the close method to close + * both the Reader and the Response object, ensuring proper resource management and preventing + * premature closure of the underlying HTTP connection. + */ +public class ResponseBodyReader extends FilterReader { + private final Response response; + + /** + * Constructs a ResponseBodyReader that wraps the Reader from the given OkHttp Response object. + * + * @param response the OkHttp Response object from which the Reader is retrieved + * @throws IOException if an I/O error occurs while retrieving the Reader + */ + public ResponseBodyReader(Response response) throws IOException { + super(response.body().charStream()); + this.response = response; + } + + /** + * Closes the Reader and the associated OkHttp Response object. This ensures that the + * underlying HTTP connection is properly closed after the reader is no longer needed. + * + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + super.close(); + response.close(); // Ensure the response is closed when the reader is closed + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java b/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java new file mode 100644 index 00000000..7a28c3c9 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java @@ -0,0 +1,79 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import okhttp3.Interceptor; +import okhttp3.Response; + +import java.io.IOException; +import java.time.Duration; +import java.util.Optional; +import java.util.Random; + +public class RetryInterceptor implements Interceptor { + + private static final Duration ONE_SECOND = Duration.ofSeconds(1); + private final ExponentialBackoff backoff; + private final Random random = new Random(); + + public RetryInterceptor(int maxRetries) { + this.backoff = new ExponentialBackoff(maxRetries); + } + + @Override + public Response intercept(Chain chain) throws IOException { + Response response = chain.proceed(chain.request()); + + if (shouldRetry(response.code())) { + return retryChain(response, chain); + } + + return response; + } + + private Response retryChain(Response response, Chain chain) throws IOException { + Optional nextBackoff = this.backoff.nextBackoff(); + while (nextBackoff.isPresent()) { + try { + Thread.sleep(nextBackoff.get().toMillis()); + } catch (InterruptedException e) { + throw new IOException("Interrupted while trying request", e); + } + response.close(); + response = chain.proceed(chain.request()); + if (shouldRetry(response.code())) { + nextBackoff = this.backoff.nextBackoff(); + } else { + return response; + } + } + + return response; + } + + private static boolean shouldRetry(int statusCode) { + return statusCode == 408 || statusCode == 429 || statusCode >= 500; + } + + private final class ExponentialBackoff { + + private final int maxNumRetries; + + private int retryNumber = 0; + + ExponentialBackoff(int maxNumRetries) { + this.maxNumRetries = maxNumRetries; + } + + public Optional nextBackoff() { + retryNumber += 1; + if (retryNumber > maxNumRetries) { + return Optional.empty(); + } + + int upperBound = (int) Math.pow(2, retryNumber); + return Optional.of(ONE_SECOND.multipliedBy(random.nextInt(upperBound))); + } + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/Stream.java b/v2/src/main/java/com/skyflow/generated/rest/core/Stream.java new file mode 100644 index 00000000..f037712a --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/Stream.java @@ -0,0 +1,97 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.io.Reader; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Scanner; + +/** + * The {@code Stream} class implements {@link Iterable} to provide a simple mechanism for reading and parsing + * objects of a given type from data streamed via a {@link Reader} using a specified delimiter. + *

+ * {@code Stream} assumes that data is being pushed to the provided {@link Reader} asynchronously and utilizes a + * {@code Scanner} to block during iteration if the next object is not available. + * + * @param The type of objects in the stream. + */ +public final class Stream implements Iterable { + /** + * The {@link Class} of the objects in the stream. + */ + private final Class valueType; + /** + * The {@link Scanner} used for reading from the input stream and blocking when needed during iteration. + */ + private final Scanner scanner; + + /** + * Constructs a new {@code Stream} with the specified value type, reader, and delimiter. + * + * @param valueType The class of the objects in the stream. + * @param reader The reader that provides the streamed data. + * @param delimiter The delimiter used to separate elements in the stream. + */ + public Stream(Class valueType, Reader reader, String delimiter) { + this.scanner = new Scanner(reader).useDelimiter(delimiter); + this.valueType = valueType; + } + + /** + * Returns an iterator over the elements in this stream that blocks during iteration when the next object is + * not yet available. + * + * @return An iterator that can be used to traverse the elements in the stream. + */ + @Override + public Iterator iterator() { + return new Iterator() { + /** + * Returns {@code true} if there are more elements in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return {@code true} if there are more elements, {@code false} otherwise. + */ + @Override + public boolean hasNext() { + return scanner.hasNext(); + } + + /** + * Returns the next element in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return The next element in the stream. + * @throws NoSuchElementException If there are no more elements in the stream. + */ + @Override + public T next() { + if (!scanner.hasNext()) { + throw new NoSuchElementException(); + } else { + try { + T parsedResponse = ObjectMappers.JSON_MAPPER.readValue( + scanner.next().trim(), valueType); + return parsedResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + /** + * Removing elements from {@code Stream} is not supported. + * + * @throws UnsupportedOperationException Always, as removal is not supported. + */ + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/Suppliers.java b/v2/src/main/java/com/skyflow/generated/rest/core/Suppliers.java new file mode 100644 index 00000000..307d5852 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/core/Suppliers.java @@ -0,0 +1,23 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +public final class Suppliers { + private Suppliers() {} + + public static Supplier memoize(Supplier delegate) { + AtomicReference value = new AtomicReference<>(); + return () -> { + T val = value.get(); + if (val == null) { + val = value.updateAndGet(cur -> cur == null ? Objects.requireNonNull(delegate.get()) : cur); + } + return val; + }; + } +} diff --git a/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java rename to v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java diff --git a/src/main/java/com/skyflow/generated/rest/errors/InternalServerError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/InternalServerError.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/errors/InternalServerError.java rename to v2/src/main/java/com/skyflow/generated/rest/errors/InternalServerError.java diff --git a/src/main/java/com/skyflow/generated/rest/errors/NotFoundError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/NotFoundError.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/errors/NotFoundError.java rename to v2/src/main/java/com/skyflow/generated/rest/errors/NotFoundError.java diff --git a/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java rename to v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncAuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncAuditClient.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/resources/audit/AsyncAuditClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncAuditClient.java index 0064558d..7e2719f2 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncAuditClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncAuditClient.java @@ -7,6 +7,7 @@ import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.resources.audit.requests.AuditServiceListAuditEventsRequest; import com.skyflow.generated.rest.types.V1AuditResponse; + import java.util.concurrent.CompletableFuture; public class AsyncAuditClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java similarity index 95% rename from src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java index 875ca259..e1516eaf 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java @@ -4,27 +4,15 @@ package com.skyflow.generated.rest.resources.audit; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.audit.requests.AuditServiceListAuditEventsRequest; import com.skyflow.generated.rest.types.V1AuditResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawAuditClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/AuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AuditClient.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/audit/AuditClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/AuditClient.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java similarity index 95% rename from src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java index bfec3bf2..68cd5e3b 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java @@ -4,23 +4,13 @@ package com.skyflow.generated.rest.resources.audit; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.audit.requests.AuditServiceListAuditEventsRequest; import com.skyflow.generated.rest.types.V1AuditResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawAuditClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java similarity index 98% rename from src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java index 8b6686e4..e9f8cf12 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java @@ -3,26 +3,16 @@ */ package com.skyflow.generated.rest.resources.audit.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsActionType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextAccessType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextActorType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextAuthMode; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsResourceType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestSortOpsOrderBy; +import com.skyflow.generated.rest.resources.audit.types.*; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = AuditServiceListAuditEventsRequest.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsActionType.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsActionType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsActionType.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsActionType.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAccessType.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAccessType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAccessType.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAccessType.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextActorType.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextActorType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextActorType.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextActorType.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAuthMode.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAuthMode.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAuthMode.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsContextAuthMode.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsResourceType.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsResourceType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsResourceType.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestFilterOpsResourceType.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestSortOpsOrderBy.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestSortOpsOrderBy.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestSortOpsOrderBy.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/audit/types/AuditServiceListAuditEventsRequestSortOpsOrderBy.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncBinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncBinLookupClient.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncBinLookupClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncBinLookupClient.java index f10ed979..fb2d07d0 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncBinLookupClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncBinLookupClient.java @@ -7,6 +7,7 @@ import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.resources.binlookup.requests.V1BinListRequest; import com.skyflow.generated.rest.types.V1BinListResponse; + import java.util.concurrent.CompletableFuture; public class AsyncBinLookupClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java similarity index 88% rename from src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java index 2a3f5f4f..9cf03c7d 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java @@ -4,28 +4,15 @@ package com.skyflow.generated.rest.resources.binlookup; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.binlookup.requests.V1BinListRequest; import com.skyflow.generated.rest.types.V1BinListResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawBinLookupClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/binlookup/BinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/BinLookupClient.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/binlookup/BinLookupClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/BinLookupClient.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java similarity index 87% rename from src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java index bb08039b..21e77017 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java @@ -4,24 +4,13 @@ package com.skyflow.generated.rest.resources.binlookup; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.binlookup.requests.V1BinListRequest; import com.skyflow.generated.rest.types.V1BinListResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawBinLookupClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java index af827e01..def40293 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java @@ -3,21 +3,12 @@ */ package com.skyflow.generated.rest.resources.binlookup.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1VaultSchemaConfig; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BinListRequest.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java index 1f157223..01031423 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java @@ -5,20 +5,11 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; + import java.util.concurrent.CompletableFuture; public class AsyncFilesClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java similarity index 96% rename from src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java index 014f3cf8..e7f008e8 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java @@ -4,44 +4,20 @@ package com.skyflow.generated.rest.resources.files; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawFilesClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java index 8d083d76..bcda96e6 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java @@ -5,17 +5,7 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java similarity index 96% rename from src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java index 164c4d18..d277d224 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java @@ -4,40 +4,18 @@ package com.skyflow.generated.rest.resources.files; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawFilesClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java similarity index 98% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java index d1cadca3..c2baa931 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java @@ -3,13 +3,7 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem; @@ -17,13 +11,10 @@ import com.skyflow.generated.rest.types.FileDataDeidentifyAudio; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileAudioRequestDeidentifyAudio.Builder.class) public final class DeidentifyFileAudioRequestDeidentifyAudio { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java index 5b6a653f..1844a116 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyPdf; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileDocumentPdfRequestDeidentifyPdf.Builder.class) public final class DeidentifyFileDocumentPdfRequestDeidentifyPdf { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java index 015bba9e..25ddea9c 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java @@ -3,13 +3,7 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileImageRequestDeidentifyImageEntityTypesItem; @@ -17,13 +11,10 @@ import com.skyflow.generated.rest.types.FileDataDeidentifyImage; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileImageRequestDeidentifyImage.Builder.class) public final class DeidentifyFileImageRequestDeidentifyImage { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java index c2cdcfb5..62d77229 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestEntityTypesItem; import com.skyflow.generated.rest.types.FileData; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequest.Builder.class) public final class DeidentifyFileRequest { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java index fc3db52a..c4d9841d 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyDocumentEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyDocument; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyDocument.Builder.class) public final class DeidentifyFileRequestDeidentifyDocument { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java index f45802ec..e1cea77f 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyPresentationEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyPresentation; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyPresentation.Builder.class) public final class DeidentifyFileRequestDeidentifyPresentation { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java index 93ea921a..10ca8feb 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifySpreadsheet; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifySpreadsheet.Builder.class) public final class DeidentifyFileRequestDeidentifySpreadsheet { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java index b579fe1b..e3f555b8 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyStructuredText; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyStructuredText.Builder.class) public final class DeidentifyFileRequestDeidentifyStructuredText { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java index 7a7c6615..8457c790 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyTextEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyText; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyText.Builder.class) public final class DeidentifyFileRequestDeidentifyText { diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java similarity index 86% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java index 490392f1..cde24227 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java index 0f5e79ab..5cd22747 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java @@ -3,22 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.FileDataReidentifyFile; import com.skyflow.generated.rest.types.Format; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ReidentifyFileRequestReidentifyFile.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageMaskingMethod.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageMaskingMethod.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageMaskingMethod.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileImageRequestDeidentifyImageMaskingMethod.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyDocumentEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyDocumentEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyDocumentEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyDocumentEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyPresentationEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyPresentationEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyPresentationEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyPresentationEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyTextEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyTextEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyTextEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestDeidentifyTextEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyFileRequestEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncGuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncGuardrailsClient.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncGuardrailsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncGuardrailsClient.java index af874ecd..fa45ee60 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncGuardrailsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncGuardrailsClient.java @@ -7,6 +7,7 @@ import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.resources.guardrails.requests.DetectGuardrailsRequest; import com.skyflow.generated.rest.types.DetectGuardrailsResponse; + import java.util.concurrent.CompletableFuture; public class AsyncGuardrailsClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java similarity index 89% rename from src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java index 0088d7a3..80853472 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java @@ -4,31 +4,18 @@ package com.skyflow.generated.rest.resources.guardrails; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; import com.skyflow.generated.rest.resources.guardrails.requests.DetectGuardrailsRequest; import com.skyflow.generated.rest.types.DetectGuardrailsResponse; import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawGuardrailsClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/guardrails/GuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/GuardrailsClient.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/guardrails/GuardrailsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/GuardrailsClient.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java similarity index 87% rename from src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java index 0223134b..5bf5c31a 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java @@ -4,27 +4,16 @@ package com.skyflow.generated.rest.resources.guardrails; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; import com.skyflow.generated.rest.resources.guardrails.requests.DetectGuardrailsRequest; import com.skyflow.generated.rest.types.DetectGuardrailsResponse; import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawGuardrailsClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java index 9063fed8..75250f8c 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.resources.guardrails.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectGuardrailsRequest.Builder.class) public final class DetectGuardrailsRequest { diff --git a/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java index 894c97b5..cab967a7 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java @@ -7,6 +7,7 @@ import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.types.V1GetQueryResponse; + import java.util.concurrent.CompletableFuture; public class AsyncQueryClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java index 96e2dc0b..7b8c9383 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java @@ -4,28 +4,15 @@ package com.skyflow.generated.rest.resources.query; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.types.V1GetQueryResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawQueryClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java index 3e5bee51..ec88ae93 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java @@ -4,24 +4,13 @@ package com.skyflow.generated.rest.resources.query; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.types.V1GetQueryResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawQueryClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java similarity index 94% rename from src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java index 60565eb5..000cd685 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.resources.query.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java similarity index 96% rename from src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java index a810f142..b1c9ae18 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java @@ -4,54 +4,21 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.ErrorResponse; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.MultipartBody; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawRecordsClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java index c6925b50..ed7240c9 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java @@ -5,24 +5,9 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; + import java.io.File; import java.util.Optional; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java similarity index 95% rename from src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java index d1b607a0..29530b56 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java @@ -4,50 +4,19 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.ErrorResponse; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; +import okhttp3.*; + import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Optional; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.MultipartBody; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawRecordsClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java index 7b4599c6..7cf3e02b 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java @@ -5,24 +5,10 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.RawRecordsClient; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; + import java.io.File; import java.util.Optional; diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java similarity index 88% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java index fe805970..3efb0a98 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java index 48586839..c1997213 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1BatchRecord; import com.skyflow.generated.rest.types.V1Byot; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBatchOperationBody.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java similarity index 85% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java index b417adbb..4b9dcced 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBulkDeleteRecordBody.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java similarity index 96% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java index 22c9090c..9b59168a 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java @@ -3,23 +3,13 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.records.types.RecordServiceBulkGetRecordRequestOrderBy; import com.skyflow.generated.rest.resources.records.types.RecordServiceBulkGetRecordRequestRedaction; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBulkGetRecordRequest.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java index eef17665..91317d02 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java @@ -3,22 +3,12 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.records.types.RecordServiceGetRecordRequestRedaction; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceGetRecordRequest.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java index e1de00f7..e832e396 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1Byot; import com.skyflow.generated.rest.types.V1FieldRecords; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceInsertRecordBody.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java index e52af2e4..f5c7a229 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java @@ -3,17 +3,12 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1Byot; import com.skyflow.generated.rest.types.V1FieldRecords; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java similarity index 95% rename from src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java index f162530c..81a9f837 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java @@ -3,20 +3,15 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = UploadFileV2Request.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestOrderBy.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestOrderBy.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestOrderBy.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestOrderBy.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestRedaction.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestRedaction.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestRedaction.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceBulkGetRecordRequestRedaction.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceGetRecordRequestRedaction.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceGetRecordRequestRedaction.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceGetRecordRequestRedaction.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/records/types/RecordServiceGetRecordRequestRedaction.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java similarity index 94% rename from src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java index 96428263..36b364b5 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java @@ -4,13 +4,7 @@ package com.skyflow.generated.rest.resources.strings; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; @@ -19,18 +13,11 @@ import com.skyflow.generated.rest.types.DeidentifyStringResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.IdentifyResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawStringsClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncStringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncStringsClient.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/resources/strings/AsyncStringsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncStringsClient.java index 046bb289..66ef72c5 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncStringsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncStringsClient.java @@ -9,6 +9,7 @@ import com.skyflow.generated.rest.resources.strings.requests.ReidentifyStringRequest; import com.skyflow.generated.rest.types.DeidentifyStringResponse; import com.skyflow.generated.rest.types.IdentifyResponse; + import java.util.concurrent.CompletableFuture; public class AsyncStringsClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java index a5e16949..da6bec56 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java @@ -4,13 +4,7 @@ package com.skyflow.generated.rest.resources.strings; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; @@ -19,14 +13,9 @@ import com.skyflow.generated.rest.types.DeidentifyStringResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.IdentifyResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawStringsClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/strings/StringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/StringsClient.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/strings/StringsClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/strings/StringsClient.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java index 943ddde4..06ec6cec 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java @@ -3,25 +3,16 @@ */ package com.skyflow.generated.rest.resources.strings.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.strings.types.DeidentifyStringRequestEntityTypesItem; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyStringRequest.Builder.class) public final class DeidentifyStringRequest { diff --git a/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java index 59c1aaf2..3c42390c 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java @@ -3,16 +3,11 @@ */ package com.skyflow.generated.rest.resources.strings.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.Format; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/resources/strings/types/DeidentifyStringRequestEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/types/DeidentifyStringRequestEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/strings/types/DeidentifyStringRequestEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/strings/types/DeidentifyStringRequestEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java similarity index 94% rename from src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java index fbf69580..794035bd 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java @@ -4,30 +4,17 @@ package com.skyflow.generated.rest.resources.tokens; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawTokensClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java similarity index 99% rename from src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java index 26d5ea05..621701af 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java @@ -9,6 +9,7 @@ import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; + import java.util.concurrent.CompletableFuture; public class AsyncTokensClient { diff --git a/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java index 5ed17d28..7ad69d11 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java @@ -4,26 +4,15 @@ package com.skyflow.generated.rest.resources.tokens; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawTokensClient { protected final ClientOptions clientOptions; diff --git a/src/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java diff --git a/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java index 59318aa8..52571f64 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java @@ -3,21 +3,12 @@ */ package com.skyflow.generated.rest.resources.tokens.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1DetokenizeRecordRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1DetokenizePayload.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java similarity index 85% rename from src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java rename to v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java index 9729023e..e5fc08f4 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java @@ -3,21 +3,12 @@ */ package com.skyflow.generated.rest.resources.tokens.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1TokenizeRecordRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1TokenizePayload.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/AuditEventAuditResourceType.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventAuditResourceType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/AuditEventAuditResourceType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/AuditEventAuditResourceType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java rename to v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java index 210f96c0..73aed9c1 100644 --- a/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java similarity index 87% rename from src/main/java/com/skyflow/generated/rest/types/AuditEventData.java rename to v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java index e2028fba..bab4b42a 100644 --- a/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java similarity index 89% rename from src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java rename to v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java index 1352c42f..9d3bbaed 100644 --- a/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/BatchRecordMethod.java b/v2/src/main/java/com/skyflow/generated/rest/types/BatchRecordMethod.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/BatchRecordMethod.java rename to v2/src/main/java/com/skyflow/generated/rest/types/BatchRecordMethod.java diff --git a/src/main/java/com/skyflow/generated/rest/types/ContextAccessType.java b/v2/src/main/java/com/skyflow/generated/rest/types/ContextAccessType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/ContextAccessType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ContextAccessType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/ContextAuthMode.java b/v2/src/main/java/com/skyflow/generated/rest/types/ContextAuthMode.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/ContextAuthMode.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ContextAuthMode.java diff --git a/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java index a7dd7c68..dc244be8 100644 --- a/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileExtension.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileExtension.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileExtension.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileExtension.java diff --git a/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileType.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutputProcessedFileType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java similarity index 87% rename from src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java index d2b8e5b6..d5a2ebd5 100644 --- a/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java index e831f142..1389fa0f 100644 --- a/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyStringResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java similarity index 94% rename from src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java index 9773dcc3..9cb2d319 100644 --- a/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java @@ -3,20 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectGuardrailsResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponseValidation.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponseValidation.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponseValidation.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponseValidation.java diff --git a/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java similarity index 95% rename from src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java index c97f7635..b73f7845 100644 --- a/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectRunsResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseOutputType.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseOutputType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseOutputType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseOutputType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseStatus.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseStatus.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseStatus.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponseStatus.java diff --git a/src/main/java/com/skyflow/generated/rest/types/DetokenizeRecordResponseValueType.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetokenizeRecordResponseValueType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/DetokenizeRecordResponseValueType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/DetokenizeRecordResponseValueType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java similarity index 88% rename from src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java index 565714eb..4113b998 100644 --- a/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ErrorResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java index bcc23f03..4774fa57 100644 --- a/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ErrorResponseError.Builder.class) public final class ErrorResponseError { diff --git a/src/main/java/com/skyflow/generated/rest/types/FileData.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileData.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileData.java index 7f58332e..fd6fa822 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileData.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileData.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java index 2aa88f7b..b6a5ea11 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyAudio.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudioDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudioDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudioDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudioDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java index e6390e28..5fb12fba 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyDocument.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocumentDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocumentDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocumentDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocumentDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java index 127c5f4c..bc5e2c6b 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyImage.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImageDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImageDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImageDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImageDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java index 20b0314f..5606e917 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyPdf.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java index e808f0b2..0bedabc5 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyPresentation.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentationDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentationDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentationDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentationDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java index 33478d20..dd017bb8 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifySpreadsheet.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheetDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheetDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheetDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheetDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java index dad188ce..814d51c3 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyStructuredText.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredTextDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredTextDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredTextDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredTextDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java index 79045d7a..e5c88180 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyText.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java index edea3145..9148703c 100644 --- a/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataReidentifyFile.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFileDataFormat.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFileDataFormat.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFileDataFormat.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFileDataFormat.java diff --git a/src/main/java/com/skyflow/generated/rest/types/Format.java b/v2/src/main/java/com/skyflow/generated/rest/types/Format.java similarity index 89% rename from src/main/java/com/skyflow/generated/rest/types/Format.java rename to v2/src/main/java/com/skyflow/generated/rest/types/Format.java index 68ac94ca..1563b90a 100644 --- a/src/main/java/com/skyflow/generated/rest/types/Format.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Format.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = Format.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/FormatMaskedItem.java b/v2/src/main/java/com/skyflow/generated/rest/types/FormatMaskedItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FormatMaskedItem.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FormatMaskedItem.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FormatPlaintextItem.java b/v2/src/main/java/com/skyflow/generated/rest/types/FormatPlaintextItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FormatPlaintextItem.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FormatPlaintextItem.java diff --git a/src/main/java/com/skyflow/generated/rest/types/FormatRedactedItem.java b/v2/src/main/java/com/skyflow/generated/rest/types/FormatRedactedItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/FormatRedactedItem.java rename to v2/src/main/java/com/skyflow/generated/rest/types/FormatRedactedItem.java diff --git a/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java b/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java similarity index 88% rename from src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java rename to v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java index 807aee4e..55be5699 100644 --- a/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = GooglerpcStatus.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java similarity index 89% rename from src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java index e7ae30fc..c1bd23c6 100644 --- a/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = IdentifyResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/Locations.java b/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java similarity index 94% rename from src/main/java/com/skyflow/generated/rest/types/Locations.java rename to v2/src/main/java/com/skyflow/generated/rest/types/Locations.java index 9864541a..4b95c485 100644 --- a/src/main/java/com/skyflow/generated/rest/types/Locations.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java b/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java similarity index 86% rename from src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java index 9f019b66..40e73b99 100644 --- a/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/RedactionEnumRedaction.java b/v2/src/main/java/com/skyflow/generated/rest/types/RedactionEnumRedaction.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/RedactionEnumRedaction.java rename to v2/src/main/java/com/skyflow/generated/rest/types/RedactionEnumRedaction.java diff --git a/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java index b5a4f6f5..a12660cb 100644 --- a/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutputProcessedFileExtension.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutputProcessedFileExtension.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutputProcessedFileExtension.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutputProcessedFileExtension.java diff --git a/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java index 024200d1..b7bc22ca 100644 --- a/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseOutputType.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseOutputType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseOutputType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseOutputType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseStatus.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseStatus.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseStatus.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponseStatus.java diff --git a/src/main/java/com/skyflow/generated/rest/types/RequestActionType.java b/v2/src/main/java/com/skyflow/generated/rest/types/RequestActionType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/RequestActionType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/RequestActionType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java b/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java similarity index 89% rename from src/main/java/com/skyflow/generated/rest/types/ShiftDates.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java index 2fc4b11a..37ef8cdf 100644 --- a/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ShiftDates.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/ShiftDatesEntityTypesItem.java b/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDatesEntityTypesItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/ShiftDatesEntityTypesItem.java rename to v2/src/main/java/com/skyflow/generated/rest/types/ShiftDatesEntityTypesItem.java diff --git a/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java b/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java similarity index 94% rename from src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java rename to v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java index 81c1e58d..78df8838 100644 --- a/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java rename to v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java index f8c1edb4..b703895d 100644 --- a/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = TokenTypeMapping.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingDefault.java b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingDefault.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingDefault.java rename to v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingDefault.java diff --git a/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityOnlyItem.java b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityOnlyItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityOnlyItem.java rename to v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityOnlyItem.java diff --git a/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityUnqCounterItem.java b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityUnqCounterItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityUnqCounterItem.java rename to v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingEntityUnqCounterItem.java diff --git a/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingVaultTokenItem.java b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingVaultTokenItem.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingVaultTokenItem.java rename to v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMappingVaultTokenItem.java diff --git a/src/main/java/com/skyflow/generated/rest/types/Transformations.java b/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java similarity index 87% rename from src/main/java/com/skyflow/generated/rest/types/Transformations.java rename to v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java index 12a5afc7..c9165409 100644 --- a/src/main/java/com/skyflow/generated/rest/types/Transformations.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java b/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java rename to v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java index c1ddbd58..8f5fea5a 100644 --- a/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java index d942fdcd..037b80bf 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java index c582d06d..f7ca73f0 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java similarity index 86% rename from src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java index dd23d77c..36d7ccce 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java index ca2bfdc2..a54eec6c 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponseEvent.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java similarity index 95% rename from src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java index 046c8fb4..90d9c538 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponseEventRequest.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java similarity index 89% rename from src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java index a557da82..8f5fb775 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BatchOperationResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java similarity index 97% rename from src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java index afc572cf..3f0455cc 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java similarity index 83% rename from src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java index 58472a8b..88c1c125 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BinListResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java similarity index 85% rename from src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java index ddb0d213..b7151598 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BulkDeleteRecordResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java similarity index 83% rename from src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java index c2d3790a..27878fab 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BulkGetRecordResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1Byot.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1Byot.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/V1Byot.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1Byot.java diff --git a/src/main/java/com/skyflow/generated/rest/types/V1Card.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java similarity index 96% rename from src/main/java/com/skyflow/generated/rest/types/V1Card.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java index f2a9db90..ba4f7349 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1Card.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java index 4ec85903..4d9b24eb 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java index 2f3bde14..5351d897 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java index 3cf5b59c..b6fb9cb6 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java similarity index 93% rename from src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java index ba0abbfa..dd3a9c1f 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java similarity index 84% rename from src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java index 74f4f6e6..53660cbe 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1DetokenizeResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java index dfbccb8b..b64b8792 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1FileAvScanStatus.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1FileAvScanStatus.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/V1FileAvScanStatus.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1FileAvScanStatus.java diff --git a/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java index f5669085..43a86ae0 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java similarity index 87% rename from src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java index 4bd67013..3138c766 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java similarity index 83% rename from src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java index 821d1f06..a44b0f62 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1GetQueryResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java similarity index 84% rename from src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java index 0addf786..f8a00001 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1InsertRecordResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1MemberType.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1MemberType.java similarity index 100% rename from src/main/java/com/skyflow/generated/rest/types/V1MemberType.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1MemberType.java diff --git a/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java index f69719cf..17f77df6 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java index 2c15ceac..43fe264a 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java similarity index 87% rename from src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java index 201a4f60..66721fa1 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java similarity index 84% rename from src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java index 62d77bed..05e64bc0 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1TokenizeResponse.Builder.class) diff --git a/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java index 03ed7b58..d2fcbf1b 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java similarity index 92% rename from src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java index c19d1cb5..6fc09854 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java similarity index 91% rename from src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java rename to v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java index cd838305..1542ab0f 100644 --- a/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java b/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java similarity index 90% rename from src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java rename to v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java index 594b6d11..314b5942 100644 --- a/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/com/skyflow/logs/ErrorLogs.java b/v2/src/main/java/com/skyflow/logs/ErrorLogs.java similarity index 100% rename from src/main/java/com/skyflow/logs/ErrorLogs.java rename to v2/src/main/java/com/skyflow/logs/ErrorLogs.java diff --git a/src/main/java/com/skyflow/logs/InfoLogs.java b/v2/src/main/java/com/skyflow/logs/InfoLogs.java similarity index 100% rename from src/main/java/com/skyflow/logs/InfoLogs.java rename to v2/src/main/java/com/skyflow/logs/InfoLogs.java diff --git a/src/main/java/com/skyflow/utils/Constants.java b/v2/src/main/java/com/skyflow/utils/Constants.java similarity index 100% rename from src/main/java/com/skyflow/utils/Constants.java rename to v2/src/main/java/com/skyflow/utils/Constants.java diff --git a/src/main/java/com/skyflow/utils/HttpUtility.java b/v2/src/main/java/com/skyflow/utils/HttpUtility.java similarity index 100% rename from src/main/java/com/skyflow/utils/HttpUtility.java rename to v2/src/main/java/com/skyflow/utils/HttpUtility.java diff --git a/src/main/java/com/skyflow/utils/Utils.java b/v2/src/main/java/com/skyflow/utils/Utils.java similarity index 100% rename from src/main/java/com/skyflow/utils/Utils.java rename to v2/src/main/java/com/skyflow/utils/Utils.java diff --git a/src/main/java/com/skyflow/utils/logger/LogUtil.java b/v2/src/main/java/com/skyflow/utils/logger/LogUtil.java similarity index 100% rename from src/main/java/com/skyflow/utils/logger/LogUtil.java rename to v2/src/main/java/com/skyflow/utils/logger/LogUtil.java diff --git a/src/main/java/com/skyflow/utils/validations/Validations.java b/v2/src/main/java/com/skyflow/utils/validations/Validations.java similarity index 99% rename from src/main/java/com/skyflow/utils/validations/Validations.java rename to v2/src/main/java/com/skyflow/utils/validations/Validations.java index 5e528a6a..2fc748f0 100644 --- a/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/v2/src/main/java/com/skyflow/utils/validations/Validations.java @@ -11,6 +11,7 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.config.ConnectionConfig; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; @@ -21,6 +22,8 @@ import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.logs.ErrorLogs; +import com.skyflow.utils.BaseConstants; +import com.skyflow.utils.BaseUtils; import com.skyflow.utils.Constants; import com.skyflow.utils.Utils; import com.skyflow.utils.logger.LogUtil; @@ -44,6 +47,96 @@ public class Validations { private Validations() { } + public static void validateCredentials(Credentials credentials) throws SkyflowException { + int nonNullMembers = 0; + String path = credentials.getPath(); + String credentialsString = credentials.getCredentialsString(); + String token = credentials.getToken(); + String apiKey = credentials.getApiKey(); + Object context = credentials.getContext(); + ArrayList roles = credentials.getRoles(); + + if (path != null) nonNullMembers++; + if (credentialsString != null) nonNullMembers++; + if (token != null) nonNullMembers++; + if (apiKey != null) nonNullMembers++; + + if (nonNullMembers > 1) { + LogUtil.printErrorLog(ErrorLogs.MULTIPLE_TOKEN_GENERATION_MEANS_PASSED.getLog()); + throw new SkyflowException( + ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MultipleTokenGenerationMeansPassed.getMessage() + ); + } else if (nonNullMembers < 1) { + LogUtil.printErrorLog(ErrorLogs.NO_TOKEN_GENERATION_MEANS_PASSED.getLog()); + throw new SkyflowException( + ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NoTokenGenerationMeansPassed.getMessage() + ); + } else if (path != null && path.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_PATH.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialFilePath.getMessage()); + } else if (credentialsString != null && credentialsString.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_STRING.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialsString.getMessage()); + } else if (token != null && token.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_TOKEN_VALUE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyToken.getMessage()); + } else if (apiKey != null) { + if (apiKey.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_API_KEY_VALUE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyApikey.getMessage()); + } else { + Pattern pattern = Pattern.compile(Constants.API_KEY_REGEX); + Matcher matcher = pattern.matcher(apiKey); + if (!matcher.matches()) { + LogUtil.printErrorLog(ErrorLogs.INVALID_API_KEY.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidApikey.getMessage()); + } + } + } else if (roles != null) { + if (roles.isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_ROLES.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoles.getMessage()); + } else { + for (int index = 0; index < roles.size(); index++) { + String role = roles.get(index); + if (role == null || role.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_ROLE_IN_ROLES.getLog(), Integer.toString(index) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoleInRoles.getMessage()); + } + } + } + } + if (context != null) { + if (context instanceof String) { + String ctxStr = (String) context; + if (ctxStr.trim().isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); + } + } else if (context instanceof Map) { + Map ctxMap = (Map) context; + if (ctxMap.isEmpty()) { + LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); + } + Pattern ctxKeyPattern = Pattern.compile(Constants.CONTEXT_KEY_REGEX); + for (Object key : ctxMap.keySet()) { + if (key == null || !ctxKeyPattern.matcher(key.toString()).matches()) { + String keyStr = key == null ? "null" : key.toString(); + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_CONTEXT_MAP_KEY.getLog(), keyStr)); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), + Utils.parameterizedString(ErrorMessage.InvalidContextMapKey.getMessage(), keyStr)); + } + } + } else { + LogUtil.printErrorLog(ErrorLogs.INVALID_CONTEXT_TYPE.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidContextType.getMessage()); + } + } + } public static void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { String vaultId = vaultConfig.getVaultId(); @@ -159,97 +252,6 @@ public static void validateInvokeConnectionRequest(InvokeConnectionRequest invok } } - public static void validateCredentials(Credentials credentials) throws SkyflowException { - int nonNullMembers = 0; - String path = credentials.getPath(); - String credentialsString = credentials.getCredentialsString(); - String token = credentials.getToken(); - String apiKey = credentials.getApiKey(); - Object context = credentials.getContext(); - ArrayList roles = credentials.getRoles(); - - if (path != null) nonNullMembers++; - if (credentialsString != null) nonNullMembers++; - if (token != null) nonNullMembers++; - if (apiKey != null) nonNullMembers++; - - if (nonNullMembers > 1) { - LogUtil.printErrorLog(ErrorLogs.MULTIPLE_TOKEN_GENERATION_MEANS_PASSED.getLog()); - throw new SkyflowException( - ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MultipleTokenGenerationMeansPassed.getMessage() - ); - } else if (nonNullMembers < 1) { - LogUtil.printErrorLog(ErrorLogs.NO_TOKEN_GENERATION_MEANS_PASSED.getLog()); - throw new SkyflowException( - ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NoTokenGenerationMeansPassed.getMessage() - ); - } else if (path != null && path.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_PATH.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialFilePath.getMessage()); - } else if (credentialsString != null && credentialsString.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_STRING.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialsString.getMessage()); - } else if (token != null && token.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_TOKEN_VALUE.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyToken.getMessage()); - } else if (apiKey != null) { - if (apiKey.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_API_KEY_VALUE.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyApikey.getMessage()); - } else { - Pattern pattern = Pattern.compile(Constants.API_KEY_REGEX); - Matcher matcher = pattern.matcher(apiKey); - if (!matcher.matches()) { - LogUtil.printErrorLog(ErrorLogs.INVALID_API_KEY.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidApikey.getMessage()); - } - } - } else if (roles != null) { - if (roles.isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_ROLES.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoles.getMessage()); - } else { - for (int index = 0; index < roles.size(); index++) { - String role = roles.get(index); - if (role == null || role.trim().isEmpty()) { - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.EMPTY_OR_NULL_ROLE_IN_ROLES.getLog(), Integer.toString(index) - )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoleInRoles.getMessage()); - } - } - } - } - if (context != null) { - if (context instanceof String) { - String ctxStr = (String) context; - if (ctxStr.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); - } - } else if (context instanceof Map) { - Map ctxMap = (Map) context; - if (ctxMap.isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); - } - Pattern ctxKeyPattern = Pattern.compile(Constants.CONTEXT_KEY_REGEX); - for (Object key : ctxMap.keySet()) { - if (key == null || !ctxKeyPattern.matcher(key.toString()).matches()) { - String keyStr = key == null ? "null" : key.toString(); - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.INVALID_CONTEXT_MAP_KEY.getLog(), keyStr)); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), - Utils.parameterizedString(ErrorMessage.InvalidContextMapKey.getMessage(), keyStr)); - } - } - } else { - LogUtil.printErrorLog(ErrorLogs.INVALID_CONTEXT_TYPE.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidContextType.getMessage()); - } - } - } - public static void validateDetokenizeRequest(DetokenizeRequest detokenizeRequest) throws SkyflowException { ArrayList detokenizeData = detokenizeRequest.getDetokenizeData(); if (detokenizeData == null) { diff --git a/src/main/java/com/skyflow/vault/audit/ListEventRequest.java b/v2/src/main/java/com/skyflow/vault/audit/ListEventRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/audit/ListEventRequest.java rename to v2/src/main/java/com/skyflow/vault/audit/ListEventRequest.java diff --git a/src/main/java/com/skyflow/vault/audit/ListEventResponse.java b/v2/src/main/java/com/skyflow/vault/audit/ListEventResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/audit/ListEventResponse.java rename to v2/src/main/java/com/skyflow/vault/audit/ListEventResponse.java diff --git a/src/main/java/com/skyflow/vault/bin/GetBinRequest.java b/v2/src/main/java/com/skyflow/vault/bin/GetBinRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/bin/GetBinRequest.java rename to v2/src/main/java/com/skyflow/vault/bin/GetBinRequest.java diff --git a/src/main/java/com/skyflow/vault/bin/GetBinResponse.java b/v2/src/main/java/com/skyflow/vault/bin/GetBinResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/bin/GetBinResponse.java rename to v2/src/main/java/com/skyflow/vault/bin/GetBinResponse.java diff --git a/src/main/java/com/skyflow/vault/connection/InvokeConnectionRequest.java b/v2/src/main/java/com/skyflow/vault/connection/InvokeConnectionRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/connection/InvokeConnectionRequest.java rename to v2/src/main/java/com/skyflow/vault/connection/InvokeConnectionRequest.java diff --git a/src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java b/v2/src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java rename to v2/src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java diff --git a/src/main/java/com/skyflow/vault/controller/AuditController.java b/v2/src/main/java/com/skyflow/vault/controller/AuditController.java similarity index 100% rename from src/main/java/com/skyflow/vault/controller/AuditController.java rename to v2/src/main/java/com/skyflow/vault/controller/AuditController.java diff --git a/src/main/java/com/skyflow/vault/controller/BinLookupController.java b/v2/src/main/java/com/skyflow/vault/controller/BinLookupController.java similarity index 100% rename from src/main/java/com/skyflow/vault/controller/BinLookupController.java rename to v2/src/main/java/com/skyflow/vault/controller/BinLookupController.java diff --git a/src/main/java/com/skyflow/vault/controller/ConnectionController.java b/v2/src/main/java/com/skyflow/vault/controller/ConnectionController.java similarity index 100% rename from src/main/java/com/skyflow/vault/controller/ConnectionController.java rename to v2/src/main/java/com/skyflow/vault/controller/ConnectionController.java diff --git a/src/main/java/com/skyflow/vault/controller/DetectController.java b/v2/src/main/java/com/skyflow/vault/controller/DetectController.java similarity index 99% rename from src/main/java/com/skyflow/vault/controller/DetectController.java rename to v2/src/main/java/com/skyflow/vault/controller/DetectController.java index 873c83e1..ad25d7e2 100644 --- a/src/main/java/com/skyflow/vault/controller/DetectController.java +++ b/v2/src/main/java/com/skyflow/vault/controller/DetectController.java @@ -8,12 +8,12 @@ import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.resources.files.requests.*; +import com.skyflow.generated.rest.types.*; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.resources.strings.requests.DeidentifyStringRequest; import com.skyflow.generated.rest.resources.strings.requests.ReidentifyStringRequest; -import com.skyflow.generated.rest.types.*; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.utils.Constants; @@ -352,7 +352,7 @@ private String extractBodyAsString(ApiClientApiException e) { private com.skyflow.generated.rest.types.DeidentifyFileResponse processFileByType(String fileExtension, String base64Content, DeidentifyFileRequest request, String vaultId) throws SkyflowException { switch (fileExtension.toLowerCase()) { case "txt": - com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText textFileRequest = + DeidentifyFileRequestDeidentifyText textFileRequest = super.getDeidentifyTextFileRequest(request, vaultId, base64Content); return super.getDetectFileAPi().deidentifyText(textFileRequest); @@ -424,7 +424,7 @@ public DeidentifyFileResponse getDetectRun(GetDetectRunRequest request) throws S .vaultId(vaultId) .build(); - com.skyflow.generated.rest.types.DetectRunsResponse apiResponse = + DetectRunsResponse apiResponse = super.getDetectFileAPi().getRun(runId, getRunRequest); return parseDeidentifyFileResponse(apiResponse, runId, apiResponse.getStatus().toString()); diff --git a/src/main/java/com/skyflow/vault/controller/VaultController.java b/v2/src/main/java/com/skyflow/vault/controller/VaultController.java similarity index 92% rename from src/main/java/com/skyflow/vault/controller/VaultController.java rename to v2/src/main/java/com/skyflow/vault/controller/VaultController.java index 1812b83b..2f74a584 100644 --- a/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/v2/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -17,6 +17,7 @@ import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.skyflow.VaultClient; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.RedactionType; @@ -73,7 +74,8 @@ import com.skyflow.vault.tokens.TokenizeRequest; import com.skyflow.vault.tokens.TokenizeResponse; -public final class VaultController extends VaultClient { +public final class VaultController extends VaultClient + implements IVaultController { private static final Gson GSON = new GsonBuilder().serializeNulls().create(); private static final JsonObject SKY_METADATA = Utils.getMetrics(); @@ -181,6 +183,7 @@ private static synchronized HashMap getFormattedQueryRecord(V1Fi return queryRecord; } + @Override public InsertResponse insert(InsertRequest insertRequest) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.INSERT_TRIGGERED.getLog()); V1InsertRecordResponse bulkInsertResult = null; @@ -229,9 +232,7 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio } } } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.INSERT_RECORDS_REJECTED); } LogUtil.printInfoLog(InfoLogs.INSERT_SUCCESS.getLog()); if (insertedFields.isEmpty()) { @@ -274,9 +275,7 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws } } } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.DETOKENIZE_REQUEST_REJECTED); } if (!errorRecords.isEmpty()) { @@ -331,9 +330,7 @@ public GetResponse get(GetRequest getRequest) throws SkyflowException { } } } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.GET_REQUEST_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.GET_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.GET_SUCCESS.getLog()); return new GetResponse(data, null); @@ -361,9 +358,7 @@ public UpdateResponse update(UpdateRequest updateRequest) throws SkyflowExceptio skyflowId = String.valueOf(result.getSkyflowId()); tokensMap = getFormattedUpdateRecord(result); } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.UPDATE_REQUEST_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.UPDATE_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.UPDATE_SUCCESS.getLog()); return new UpdateResponse(skyflowId, tokensMap); @@ -384,9 +379,7 @@ public DeleteResponse delete(DeleteRequest deleteRequest) throws SkyflowExceptio super.getVaultConfig().getVaultId(), deleteRequest.getTable(), deleteBody, requestOptions); LogUtil.printInfoLog(InfoLogs.DELETE_REQUEST_RESOLVED.getLog()); } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.DELETE_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.DELETE_SUCCESS.getLog()); return new DeleteResponse(result.getRecordIdResponse().orElse(Collections.emptyList())); @@ -414,9 +407,7 @@ public QueryResponse query(QueryRequest queryRequest) throws SkyflowException { } } } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.QUERY_REQUEST_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.QUERY_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.QUERY_SUCCESS.getLog()); return new QueryResponse(fields); @@ -442,9 +433,7 @@ public TokenizeResponse tokenize(TokenizeRequest tokenizeRequest) throws Skyflow } } } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.TOKENIZE_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.TOKENIZE_SUCCESS.getLog()); return new TokenizeResponse(list); @@ -481,9 +470,7 @@ public FileUploadResponse uploadFile(FileUploadRequest fileUploadRequest) throws ); } catch (ApiClientApiException e) { - String bodyString = GSON.toJson(e.body()); - LogUtil.printErrorLog(ErrorLogs.UPLOAD_FILE_REQUEST_REJECTED.getLog()); - throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.UPLOAD_FILE_REQUEST_REJECTED); } catch (IOException e) { LogUtil.printErrorLog(ErrorLogs.UPLOAD_FILE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.getMessage(), e); diff --git a/src/main/java/com/skyflow/vault/data/DeleteRequest.java b/v2/src/main/java/com/skyflow/vault/data/DeleteRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/DeleteRequest.java rename to v2/src/main/java/com/skyflow/vault/data/DeleteRequest.java diff --git a/src/main/java/com/skyflow/vault/data/DeleteResponse.java b/v2/src/main/java/com/skyflow/vault/data/DeleteResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/DeleteResponse.java rename to v2/src/main/java/com/skyflow/vault/data/DeleteResponse.java diff --git a/src/main/java/com/skyflow/vault/data/FileUploadRequest.java b/v2/src/main/java/com/skyflow/vault/data/FileUploadRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/FileUploadRequest.java rename to v2/src/main/java/com/skyflow/vault/data/FileUploadRequest.java diff --git a/src/main/java/com/skyflow/vault/data/FileUploadResponse.java b/v2/src/main/java/com/skyflow/vault/data/FileUploadResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/FileUploadResponse.java rename to v2/src/main/java/com/skyflow/vault/data/FileUploadResponse.java diff --git a/src/main/java/com/skyflow/vault/data/GetRequest.java b/v2/src/main/java/com/skyflow/vault/data/GetRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/GetRequest.java rename to v2/src/main/java/com/skyflow/vault/data/GetRequest.java diff --git a/src/main/java/com/skyflow/vault/data/GetResponse.java b/v2/src/main/java/com/skyflow/vault/data/GetResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/GetResponse.java rename to v2/src/main/java/com/skyflow/vault/data/GetResponse.java diff --git a/src/main/java/com/skyflow/vault/data/InsertRequest.java b/v2/src/main/java/com/skyflow/vault/data/InsertRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/InsertRequest.java rename to v2/src/main/java/com/skyflow/vault/data/InsertRequest.java diff --git a/src/main/java/com/skyflow/vault/data/InsertResponse.java b/v2/src/main/java/com/skyflow/vault/data/InsertResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/InsertResponse.java rename to v2/src/main/java/com/skyflow/vault/data/InsertResponse.java diff --git a/src/main/java/com/skyflow/vault/data/QueryRequest.java b/v2/src/main/java/com/skyflow/vault/data/QueryRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/QueryRequest.java rename to v2/src/main/java/com/skyflow/vault/data/QueryRequest.java diff --git a/src/main/java/com/skyflow/vault/data/QueryResponse.java b/v2/src/main/java/com/skyflow/vault/data/QueryResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/QueryResponse.java rename to v2/src/main/java/com/skyflow/vault/data/QueryResponse.java diff --git a/src/main/java/com/skyflow/vault/data/UpdateRequest.java b/v2/src/main/java/com/skyflow/vault/data/UpdateRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/UpdateRequest.java rename to v2/src/main/java/com/skyflow/vault/data/UpdateRequest.java diff --git a/src/main/java/com/skyflow/vault/data/UpdateResponse.java b/v2/src/main/java/com/skyflow/vault/data/UpdateResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/data/UpdateResponse.java rename to v2/src/main/java/com/skyflow/vault/data/UpdateResponse.java diff --git a/src/main/java/com/skyflow/vault/detect/AudioBleep.java b/v2/src/main/java/com/skyflow/vault/detect/AudioBleep.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/AudioBleep.java rename to v2/src/main/java/com/skyflow/vault/detect/AudioBleep.java diff --git a/src/main/java/com/skyflow/vault/detect/DateTransformation.java b/v2/src/main/java/com/skyflow/vault/detect/DateTransformation.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/DateTransformation.java rename to v2/src/main/java/com/skyflow/vault/detect/DateTransformation.java diff --git a/src/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java b/v2/src/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java rename to v2/src/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java diff --git a/src/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java b/v2/src/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java rename to v2/src/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java diff --git a/src/main/java/com/skyflow/vault/detect/DeidentifyTextRequest.java b/v2/src/main/java/com/skyflow/vault/detect/DeidentifyTextRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/DeidentifyTextRequest.java rename to v2/src/main/java/com/skyflow/vault/detect/DeidentifyTextRequest.java diff --git a/src/main/java/com/skyflow/vault/detect/DeidentifyTextResponse.java b/v2/src/main/java/com/skyflow/vault/detect/DeidentifyTextResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/DeidentifyTextResponse.java rename to v2/src/main/java/com/skyflow/vault/detect/DeidentifyTextResponse.java diff --git a/src/main/java/com/skyflow/vault/detect/EntityInfo.java b/v2/src/main/java/com/skyflow/vault/detect/EntityInfo.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/EntityInfo.java rename to v2/src/main/java/com/skyflow/vault/detect/EntityInfo.java diff --git a/src/main/java/com/skyflow/vault/detect/FileEntityInfo.java b/v2/src/main/java/com/skyflow/vault/detect/FileEntityInfo.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/FileEntityInfo.java rename to v2/src/main/java/com/skyflow/vault/detect/FileEntityInfo.java diff --git a/src/main/java/com/skyflow/vault/detect/FileInfo.java b/v2/src/main/java/com/skyflow/vault/detect/FileInfo.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/FileInfo.java rename to v2/src/main/java/com/skyflow/vault/detect/FileInfo.java diff --git a/src/main/java/com/skyflow/vault/detect/FileInput.java b/v2/src/main/java/com/skyflow/vault/detect/FileInput.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/FileInput.java rename to v2/src/main/java/com/skyflow/vault/detect/FileInput.java diff --git a/src/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java b/v2/src/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java rename to v2/src/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java diff --git a/src/main/java/com/skyflow/vault/detect/ReidentifyTextRequest.java b/v2/src/main/java/com/skyflow/vault/detect/ReidentifyTextRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/ReidentifyTextRequest.java rename to v2/src/main/java/com/skyflow/vault/detect/ReidentifyTextRequest.java diff --git a/src/main/java/com/skyflow/vault/detect/ReidentifyTextResponse.java b/v2/src/main/java/com/skyflow/vault/detect/ReidentifyTextResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/ReidentifyTextResponse.java rename to v2/src/main/java/com/skyflow/vault/detect/ReidentifyTextResponse.java diff --git a/src/main/java/com/skyflow/vault/detect/TextIndex.java b/v2/src/main/java/com/skyflow/vault/detect/TextIndex.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/TextIndex.java rename to v2/src/main/java/com/skyflow/vault/detect/TextIndex.java diff --git a/src/main/java/com/skyflow/vault/detect/TokenFormat.java b/v2/src/main/java/com/skyflow/vault/detect/TokenFormat.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/TokenFormat.java rename to v2/src/main/java/com/skyflow/vault/detect/TokenFormat.java diff --git a/src/main/java/com/skyflow/vault/detect/Transformations.java b/v2/src/main/java/com/skyflow/vault/detect/Transformations.java similarity index 100% rename from src/main/java/com/skyflow/vault/detect/Transformations.java rename to v2/src/main/java/com/skyflow/vault/detect/Transformations.java diff --git a/src/main/java/com/skyflow/vault/tokens/ColumnValue.java b/v2/src/main/java/com/skyflow/vault/tokens/ColumnValue.java similarity index 100% rename from src/main/java/com/skyflow/vault/tokens/ColumnValue.java rename to v2/src/main/java/com/skyflow/vault/tokens/ColumnValue.java diff --git a/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java similarity index 100% rename from src/main/java/com/skyflow/vault/tokens/DetokenizeData.java rename to v2/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java diff --git a/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java rename to v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java diff --git a/src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java rename to v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRequest.java diff --git a/src/main/java/com/skyflow/vault/tokens/DetokenizeResponse.java b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/tokens/DetokenizeResponse.java rename to v2/src/main/java/com/skyflow/vault/tokens/DetokenizeResponse.java diff --git a/src/main/java/com/skyflow/vault/tokens/TokenizeRequest.java b/v2/src/main/java/com/skyflow/vault/tokens/TokenizeRequest.java similarity index 100% rename from src/main/java/com/skyflow/vault/tokens/TokenizeRequest.java rename to v2/src/main/java/com/skyflow/vault/tokens/TokenizeRequest.java diff --git a/src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java b/v2/src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java similarity index 100% rename from src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java rename to v2/src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java diff --git a/src/main/resources/sdk.properties b/v2/src/main/resources/sdk.properties similarity index 100% rename from src/main/resources/sdk.properties rename to v2/src/main/resources/sdk.properties diff --git a/src/test/java/com/skyflow/ConnectionClientDotenvTests.java b/v2/src/test/java/com/skyflow/ConnectionClientDotenvTests.java similarity index 100% rename from src/test/java/com/skyflow/ConnectionClientDotenvTests.java rename to v2/src/test/java/com/skyflow/ConnectionClientDotenvTests.java diff --git a/src/test/java/com/skyflow/ConnectionClientTests.java b/v2/src/test/java/com/skyflow/ConnectionClientTests.java similarity index 100% rename from src/test/java/com/skyflow/ConnectionClientTests.java rename to v2/src/test/java/com/skyflow/ConnectionClientTests.java diff --git a/src/test/java/com/skyflow/SkyflowTests.java b/v2/src/test/java/com/skyflow/SkyflowTests.java similarity index 94% rename from src/test/java/com/skyflow/SkyflowTests.java rename to v2/src/test/java/com/skyflow/SkyflowTests.java index 983419a7..360daddd 100644 --- a/src/test/java/com/skyflow/SkyflowTests.java +++ b/v2/src/test/java/com/skyflow/SkyflowTests.java @@ -1,7 +1,7 @@ package com.skyflow; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.config.ConnectionConfig; -import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; import com.skyflow.enums.LogLevel; @@ -60,7 +60,7 @@ public static void setup() { @Test public void testAddingInvalidVaultConfigInSkyflowBuilder() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(""); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -75,7 +75,7 @@ public void testAddingInvalidVaultConfigInSkyflowBuilder() { @Test public void testAddingInvalidVaultConfigInSkyflowClient() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(""); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -91,7 +91,7 @@ public void testAddingInvalidVaultConfigInSkyflowClient() { @Test public void testAddingValidVaultConfigInSkyflowClient() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -105,7 +105,7 @@ public void testAddingValidVaultConfigInSkyflowClient() { @Test public void testAddingExistingVaultConfigInSkyflowClient() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -121,7 +121,7 @@ public void testAddingExistingVaultConfigInSkyflowClient() { @Test public void testUpdatingNonExistentVaultConfigInSkyflowBuilder() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -136,7 +136,7 @@ public void testUpdatingNonExistentVaultConfigInSkyflowBuilder() { @Test public void testUpdatingNonExistentVaultConfigInSkyflowClient() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -154,7 +154,7 @@ public void testUpdatingNonExistentVaultConfigInSkyflowClient() { @Test public void testUpdatingValidVaultConfigInSkyflowClient() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -176,7 +176,7 @@ public void testUpdatingValidVaultConfigInSkyflowClient() { @Test public void testUpdateVaultConfigNullCredentialsFallsBackToPrevious() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -188,7 +188,7 @@ public void testUpdateVaultConfigNullCredentialsFallsBackToPrevious() { Skyflow skyflowClient = Skyflow.builder().addVaultConfig(config).build(); // Update with null credentials — should retain previous credentials value - VaultConfig partialUpdate = new VaultConfig(); + BaseVaultConfig partialUpdate = new BaseVaultConfig(); partialUpdate.setVaultId(vaultID); partialUpdate.setClusterId(clusterID); skyflowClient.updateVaultConfig(partialUpdate); @@ -212,7 +212,7 @@ public void testRemovingNonExistentVaultConfigInSkyflowBuilder() { @Test public void testRemovingNonExistentVaultConfigInSkyflowClient() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -239,7 +239,7 @@ public void testRemovingValidVaultConfigInSkyflowClient() { public void testGettingNonExistentVaultConfigInSkyflowClient() { try { Skyflow skyflowClient = Skyflow.builder().build(); - VaultConfig config = skyflowClient.getVaultConfig(vaultID); + BaseVaultConfig config = skyflowClient.getVaultConfig(vaultID); Assert.assertNull(config); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); @@ -261,12 +261,12 @@ public void testGettingAlreadyRemovedVaultFromEmptyConfigs() { @Test public void testGettingAlreadyRemovedVaultFromNonEmptyConfigs() { try { - VaultConfig primaryConfig = new VaultConfig(); + BaseVaultConfig primaryConfig = new BaseVaultConfig(); primaryConfig.setVaultId(vaultID); primaryConfig.setClusterId(clusterID); primaryConfig.setEnv(Env.SANDBOX); - VaultConfig secondaryConfig = new VaultConfig(); + BaseVaultConfig secondaryConfig = new BaseVaultConfig(); secondaryConfig.setVaultId(vaultID + "123"); secondaryConfig.setClusterId(clusterID); secondaryConfig.setEnv(Env.SANDBOX); @@ -475,7 +475,7 @@ public void testAddingInvalidSkyflowCredentialsInSkyflowBuilder() { @Test public void testUpdatingValidSkyflowCredentialsInSkyflowClient() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); @@ -574,7 +574,7 @@ public void testVaultMethodWithNoConfig() { @Test public void testVaultMethodWithValidConfig() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -589,7 +589,7 @@ public void testVaultMethodWithValidConfig() { @Test public void testVaultMethodWithInvalidVaultId() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -658,7 +658,7 @@ public void testDetectMethodWithNoConfig() { @Test public void testDetectMethodWithValidConfig() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -673,7 +673,7 @@ public void testDetectMethodWithValidConfig() { @Test public void testDetectMethodWithInvalidVaultId() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -689,7 +689,7 @@ public void testDetectMethodWithInvalidVaultId() { @Test public void testUpdateVaultConfig_withNewClusterIdAndCredentials_updatesAllFields() { try { - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.DEV); @@ -702,7 +702,7 @@ public void testUpdateVaultConfig_withNewClusterIdAndCredentials_updatesAllField // the non-null (true) branches for all three ternaries in findAndUpdateVaultConfig Credentials newCreds = new Credentials(); newCreds.setToken("updated-token-value"); - VaultConfig update = new VaultConfig(); + BaseVaultConfig update = new BaseVaultConfig(); update.setVaultId(vaultID); update.setClusterId(newClusterID); update.setEnv(Env.PROD); @@ -751,14 +751,14 @@ public void testUpdateVaultConfig_withNullEnv_fallsBackToPreviousEnv() { try { Credentials creds = new Credentials(); creds.setToken(token); - VaultConfig initial = new VaultConfig(); + BaseVaultConfig initial = new BaseVaultConfig(); initial.setVaultId(vaultID); initial.setClusterId(clusterID); initial.setEnv(Env.SANDBOX); initial.setCredentials(creds); Skyflow skyflowClient = Skyflow.builder().addVaultConfig(initial).build(); - VaultConfig updateWithNullEnv = new VaultConfig() { + BaseVaultConfig updateWithNullEnv = new BaseVaultConfig() { @Override public Env getEnv() { return null; } }; updateWithNullEnv.setVaultId(vaultID); @@ -781,7 +781,7 @@ public void testFindAndUpdateVaultConfig_withNullClusterId_fallsBackToPreviousCl try { Credentials creds = new Credentials(); creds.setToken(token); - VaultConfig initial = new VaultConfig(); + BaseVaultConfig initial = new BaseVaultConfig(); initial.setVaultId(vaultID); initial.setClusterId(clusterID); initial.setEnv(Env.DEV); @@ -792,17 +792,17 @@ public void testFindAndUpdateVaultConfig_withNullClusterId_fallsBackToPreviousCl builderField.setAccessible(true); Object builder = builderField.get(skyflowClient); - VaultConfig nullClusterConfig = new VaultConfig(); + BaseVaultConfig nullClusterConfig = new BaseVaultConfig(); nullClusterConfig.setVaultId(vaultID); // Override clusterId field to null via reflection (setter enforces non-null) - java.lang.reflect.Field clusterIdField = VaultConfig.class.getDeclaredField("clusterId"); + java.lang.reflect.Field clusterIdField = BaseVaultConfig.class.getDeclaredField("clusterId"); clusterIdField.setAccessible(true); clusterIdField.set(nullClusterConfig, null); java.lang.reflect.Method method = builder.getClass().getDeclaredMethod( - "findAndUpdateVaultConfig", VaultConfig.class); + "findAndUpdateVaultConfig", BaseVaultConfig.class); method.setAccessible(true); - VaultConfig result = (VaultConfig) method.invoke(builder, nullClusterConfig); + BaseVaultConfig result = (BaseVaultConfig) method.invoke(builder, nullClusterConfig); Assert.assertEquals(clusterID, result.getClusterId()); } catch (SkyflowException e) { diff --git a/src/test/java/com/skyflow/VaultClientDotenvTests.java b/v2/src/test/java/com/skyflow/VaultClientDotenvTests.java similarity index 98% rename from src/test/java/com/skyflow/VaultClientDotenvTests.java rename to v2/src/test/java/com/skyflow/VaultClientDotenvTests.java index 1a54b13d..2e71816a 100644 --- a/src/test/java/com/skyflow/VaultClientDotenvTests.java +++ b/v2/src/test/java/com/skyflow/VaultClientDotenvTests.java @@ -1,5 +1,6 @@ package com.skyflow; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; diff --git a/src/test/java/com/skyflow/VaultClientTests.java b/v2/src/test/java/com/skyflow/VaultClientTests.java similarity index 99% rename from src/test/java/com/skyflow/VaultClientTests.java rename to v2/src/test/java/com/skyflow/VaultClientTests.java index d98f5964..db04cae4 100644 --- a/src/test/java/com/skyflow/VaultClientTests.java +++ b/v2/src/test/java/com/skyflow/VaultClientTests.java @@ -1,12 +1,14 @@ package com.skyflow; +import com.skyflow.config.VaultConfig; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.*; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.SkyflowException; -import com.skyflow.generated.rest.resources.files.FilesClient; import com.skyflow.generated.rest.resources.files.requests.*; +import com.skyflow.generated.rest.resources.files.FilesClient; +import com.skyflow.generated.rest.types.*; import com.skyflow.generated.rest.resources.query.QueryClient; import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; @@ -18,7 +20,6 @@ import com.skyflow.generated.rest.resources.tokens.TokensClient; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; -import com.skyflow.generated.rest.types.*; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.UpdateRequest; import com.skyflow.vault.detect.*; @@ -707,7 +708,7 @@ public void testGetDeidentifyTextFileRequest() { String vaultId = "vault123"; String base64Content = "base64string"; - com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText textRequest = + DeidentifyFileRequestDeidentifyText textRequest = vaultClient.getDeidentifyTextFileRequest(request, vaultId, base64Content); Assert.assertEquals(vaultId, textRequest.getVaultId()); diff --git a/src/test/java/com/skyflow/config/ConnectionConfigTests.java b/v2/src/test/java/com/skyflow/config/ConnectionConfigTests.java similarity index 100% rename from src/test/java/com/skyflow/config/ConnectionConfigTests.java rename to v2/src/test/java/com/skyflow/config/ConnectionConfigTests.java diff --git a/src/test/java/com/skyflow/config/CredentialsTests.java b/v2/src/test/java/com/skyflow/config/CredentialsTests.java similarity index 100% rename from src/test/java/com/skyflow/config/CredentialsTests.java rename to v2/src/test/java/com/skyflow/config/CredentialsTests.java diff --git a/src/test/java/com/skyflow/config/ManagementConfigTest.java b/v2/src/test/java/com/skyflow/config/ManagementConfigTest.java similarity index 100% rename from src/test/java/com/skyflow/config/ManagementConfigTest.java rename to v2/src/test/java/com/skyflow/config/ManagementConfigTest.java diff --git a/src/test/java/com/skyflow/config/VaultConfigTests.java b/v2/src/test/java/com/skyflow/config/VaultConfigTests.java similarity index 91% rename from src/test/java/com/skyflow/config/VaultConfigTests.java rename to v2/src/test/java/com/skyflow/config/VaultConfigTests.java index b99f6c9b..31305c0c 100644 --- a/src/test/java/com/skyflow/config/VaultConfigTests.java +++ b/v2/src/test/java/com/skyflow/config/VaultConfigTests.java @@ -30,7 +30,7 @@ public static void setup() { @Test public void testValidVaultConfigWithCredentialsInValidations() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -49,7 +49,7 @@ public void testValidVaultConfigWithCredentialsInValidations() { @Test public void testValidVaultConfigWithoutCredentialsInValidations() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -67,7 +67,7 @@ public void testValidVaultConfigWithoutCredentialsInValidations() { @Test public void testDefaultEnvInVaultConfigWithCredentialsInValidations() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setCredentials(credentials); @@ -85,7 +85,7 @@ public void testDefaultEnvInVaultConfigWithCredentialsInValidations() { @Test public void testDefaultEnvInVaultConfigWithoutCredentialsInValidations() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(null); @@ -102,7 +102,7 @@ public void testDefaultEnvInVaultConfigWithoutCredentialsInValidations() { @Test public void testNoVaultIdInVaultConfigInValidations() { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); try { vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -117,7 +117,7 @@ public void testNoVaultIdInVaultConfigInValidations() { @Test public void testEmptyVaultIdInVaultConfigInValidations() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(""); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -132,7 +132,7 @@ public void testEmptyVaultIdInVaultConfigInValidations() { @Test public void testNoClusterIdInVaultConfigInValidations() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setEnv(Env.SANDBOX); Validations.validateVaultConfig(vaultConfig); @@ -146,7 +146,7 @@ public void testNoClusterIdInVaultConfigInValidations() { @Test public void testEmptyClusterIdInVaultConfigInValidations() { try { - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(""); vaultConfig.setEnv(Env.SANDBOX); diff --git a/src/test/java/com/skyflow/enums/DeidentifyFileStatusTest.java b/v2/src/test/java/com/skyflow/enums/DeidentifyFileStatusTest.java similarity index 100% rename from src/test/java/com/skyflow/enums/DeidentifyFileStatusTest.java rename to v2/src/test/java/com/skyflow/enums/DeidentifyFileStatusTest.java diff --git a/src/test/java/com/skyflow/enums/DetectEntitiesTest.java b/v2/src/test/java/com/skyflow/enums/DetectEntitiesTest.java similarity index 100% rename from src/test/java/com/skyflow/enums/DetectEntitiesTest.java rename to v2/src/test/java/com/skyflow/enums/DetectEntitiesTest.java diff --git a/src/test/java/com/skyflow/enums/DetectOutputTranscriptionsTest.java b/v2/src/test/java/com/skyflow/enums/DetectOutputTranscriptionsTest.java similarity index 100% rename from src/test/java/com/skyflow/enums/DetectOutputTranscriptionsTest.java rename to v2/src/test/java/com/skyflow/enums/DetectOutputTranscriptionsTest.java diff --git a/src/test/java/com/skyflow/enums/MaskingMethodTest.java b/v2/src/test/java/com/skyflow/enums/MaskingMethodTest.java similarity index 100% rename from src/test/java/com/skyflow/enums/MaskingMethodTest.java rename to v2/src/test/java/com/skyflow/enums/MaskingMethodTest.java diff --git a/src/test/java/com/skyflow/enums/TokenModeTest.java b/v2/src/test/java/com/skyflow/enums/TokenModeTest.java similarity index 98% rename from src/test/java/com/skyflow/enums/TokenModeTest.java rename to v2/src/test/java/com/skyflow/enums/TokenModeTest.java index 72236a16..b65a72cb 100644 --- a/src/test/java/com/skyflow/enums/TokenModeTest.java +++ b/v2/src/test/java/com/skyflow/enums/TokenModeTest.java @@ -1,6 +1,5 @@ package com.skyflow.enums; -import com.skyflow.enums.LogLevel; import com.skyflow.generated.rest.types.V1Byot; import com.skyflow.logs.InfoLogs; import com.skyflow.utils.logger.LogUtil; diff --git a/src/test/java/com/skyflow/enums/TokenTypeTest.java b/v2/src/test/java/com/skyflow/enums/TokenTypeTest.java similarity index 100% rename from src/test/java/com/skyflow/enums/TokenTypeTest.java rename to v2/src/test/java/com/skyflow/enums/TokenTypeTest.java diff --git a/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java b/v2/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java similarity index 100% rename from src/test/java/com/skyflow/errors/SkyflowExceptionTest.java rename to v2/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java diff --git a/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java b/v2/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java similarity index 100% rename from src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java rename to v2/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java diff --git a/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java b/v2/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java similarity index 100% rename from src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java rename to v2/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java diff --git a/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java b/v2/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java similarity index 100% rename from src/test/java/com/skyflow/serviceaccount/util/TokenTests.java rename to v2/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java diff --git a/src/test/java/com/skyflow/utils/HttpUtilityTests.java b/v2/src/test/java/com/skyflow/utils/HttpUtilityTests.java similarity index 100% rename from src/test/java/com/skyflow/utils/HttpUtilityTests.java rename to v2/src/test/java/com/skyflow/utils/HttpUtilityTests.java diff --git a/src/test/java/com/skyflow/utils/UtilsTests.java b/v2/src/test/java/com/skyflow/utils/UtilsTests.java similarity index 100% rename from src/test/java/com/skyflow/utils/UtilsTests.java rename to v2/src/test/java/com/skyflow/utils/UtilsTests.java diff --git a/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java b/v2/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java similarity index 100% rename from src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java rename to v2/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java diff --git a/src/test/java/com/skyflow/vault/BinAuditTests.java b/v2/src/test/java/com/skyflow/vault/BinAuditTests.java similarity index 100% rename from src/test/java/com/skyflow/vault/BinAuditTests.java rename to v2/src/test/java/com/skyflow/vault/BinAuditTests.java diff --git a/src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java b/v2/src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java similarity index 100% rename from src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java rename to v2/src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java diff --git a/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java b/v2/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java similarity index 99% rename from src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java rename to v2/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java index a258e01d..ddbe519e 100644 --- a/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java +++ b/v2/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java @@ -2,7 +2,6 @@ import com.skyflow.Skyflow; import com.skyflow.config.ConnectionConfig; -import com.skyflow.config.Credentials; import com.skyflow.enums.LogLevel; import com.skyflow.enums.RequestMethod; import com.skyflow.errors.ErrorCode; diff --git a/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java b/v2/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java similarity index 99% rename from src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java rename to v2/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java index 2b8379bc..f0347eeb 100644 --- a/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java +++ b/v2/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java @@ -1,5 +1,6 @@ package com.skyflow.vault.controller; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.errors.ErrorCode; diff --git a/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java b/v2/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java similarity index 99% rename from src/test/java/com/skyflow/vault/controller/DetectControllerTests.java rename to v2/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java index 52bb2be4..83ad9d5c 100644 --- a/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java +++ b/v2/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java @@ -2,8 +2,7 @@ import com.skyflow.Skyflow; import com.skyflow.VaultClient; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.DetectEntities; import com.skyflow.enums.Env; import com.skyflow.enums.LogLevel; @@ -56,7 +55,7 @@ public class DetectControllerTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; private static String vaultID = null; private static String clusterID = null; - private static VaultConfig vaultConfig = null; + private static BaseVaultConfig vaultConfig = null; private static Skyflow skyflowClient = null; @BeforeClass @@ -67,7 +66,7 @@ public static void setup() throws SkyflowException { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - vaultConfig = new VaultConfig(); + vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); @@ -85,7 +84,7 @@ private static DetectController createDetectControllerWithMock(ApiClient mockApi Credentials creds = new Credentials(); creds.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); - VaultConfig config = new VaultConfig(); + BaseVaultConfig config = new BaseVaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.DEV); diff --git a/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/v2/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java similarity index 100% rename from src/test/java/com/skyflow/vault/controller/VaultControllerTests.java rename to v2/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java diff --git a/src/test/java/com/skyflow/vault/data/DeleteTests.java b/v2/src/test/java/com/skyflow/vault/data/DeleteTests.java similarity index 97% rename from src/test/java/com/skyflow/vault/data/DeleteTests.java rename to v2/src/test/java/com/skyflow/vault/data/DeleteTests.java index befc3d26..1cef1c17 100644 --- a/src/test/java/com/skyflow/vault/data/DeleteTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/DeleteTests.java @@ -1,8 +1,7 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.Env; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; @@ -35,7 +34,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/src/test/java/com/skyflow/vault/data/FileUploadTests.java b/v2/src/test/java/com/skyflow/vault/data/FileUploadTests.java similarity index 100% rename from src/test/java/com/skyflow/vault/data/FileUploadTests.java rename to v2/src/test/java/com/skyflow/vault/data/FileUploadTests.java diff --git a/src/test/java/com/skyflow/vault/data/GetTests.java b/v2/src/test/java/com/skyflow/vault/data/GetTests.java similarity index 99% rename from src/test/java/com/skyflow/vault/data/GetTests.java rename to v2/src/test/java/com/skyflow/vault/data/GetTests.java index e62c605f..ec0f112e 100644 --- a/src/test/java/com/skyflow/vault/data/GetTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/GetTests.java @@ -1,8 +1,7 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.Env; import com.skyflow.enums.RedactionType; import com.skyflow.errors.ErrorCode; @@ -43,7 +42,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/src/test/java/com/skyflow/vault/data/InsertTests.java b/v2/src/test/java/com/skyflow/vault/data/InsertTests.java similarity index 99% rename from src/test/java/com/skyflow/vault/data/InsertTests.java rename to v2/src/test/java/com/skyflow/vault/data/InsertTests.java index 030bc5ea..43211f4c 100644 --- a/src/test/java/com/skyflow/vault/data/InsertTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/InsertTests.java @@ -1,8 +1,7 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.Env; import com.skyflow.enums.TokenMode; import com.skyflow.errors.ErrorCode; @@ -42,7 +41,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/src/test/java/com/skyflow/vault/data/QueryResponseTest.java b/v2/src/test/java/com/skyflow/vault/data/QueryResponseTest.java similarity index 100% rename from src/test/java/com/skyflow/vault/data/QueryResponseTest.java rename to v2/src/test/java/com/skyflow/vault/data/QueryResponseTest.java diff --git a/src/test/java/com/skyflow/vault/data/QueryTests.java b/v2/src/test/java/com/skyflow/vault/data/QueryTests.java similarity index 96% rename from src/test/java/com/skyflow/vault/data/QueryTests.java rename to v2/src/test/java/com/skyflow/vault/data/QueryTests.java index c8e453f5..862006f4 100644 --- a/src/test/java/com/skyflow/vault/data/QueryTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/QueryTests.java @@ -1,8 +1,7 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.Env; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; @@ -34,7 +33,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/src/test/java/com/skyflow/vault/data/UpdateTests.java b/v2/src/test/java/com/skyflow/vault/data/UpdateTests.java similarity index 99% rename from src/test/java/com/skyflow/vault/data/UpdateTests.java rename to v2/src/test/java/com/skyflow/vault/data/UpdateTests.java index 8ae1db8d..0523d6cc 100644 --- a/src/test/java/com/skyflow/vault/data/UpdateTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/UpdateTests.java @@ -1,8 +1,7 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.Env; import com.skyflow.enums.TokenMode; import com.skyflow.errors.ErrorCode; @@ -37,7 +36,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - VaultConfig vaultConfig = new VaultConfig(); + BaseVaultConfig vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/src/test/java/com/skyflow/vault/detect/DeidentifyFileRequestTest.java b/v2/src/test/java/com/skyflow/vault/detect/DeidentifyFileRequestTest.java similarity index 100% rename from src/test/java/com/skyflow/vault/detect/DeidentifyFileRequestTest.java rename to v2/src/test/java/com/skyflow/vault/detect/DeidentifyFileRequestTest.java diff --git a/src/test/java/com/skyflow/vault/detect/DeidentifyFileResponseTest.java b/v2/src/test/java/com/skyflow/vault/detect/DeidentifyFileResponseTest.java similarity index 100% rename from src/test/java/com/skyflow/vault/detect/DeidentifyFileResponseTest.java rename to v2/src/test/java/com/skyflow/vault/detect/DeidentifyFileResponseTest.java diff --git a/src/test/java/com/skyflow/vault/detect/DeidentifyTextTests.java b/v2/src/test/java/com/skyflow/vault/detect/DeidentifyTextTests.java similarity index 100% rename from src/test/java/com/skyflow/vault/detect/DeidentifyTextTests.java rename to v2/src/test/java/com/skyflow/vault/detect/DeidentifyTextTests.java diff --git a/src/test/java/com/skyflow/vault/detect/FileEntityInfoTest.java b/v2/src/test/java/com/skyflow/vault/detect/FileEntityInfoTest.java similarity index 100% rename from src/test/java/com/skyflow/vault/detect/FileEntityInfoTest.java rename to v2/src/test/java/com/skyflow/vault/detect/FileEntityInfoTest.java diff --git a/src/test/java/com/skyflow/vault/detect/FileInfoTest.java b/v2/src/test/java/com/skyflow/vault/detect/FileInfoTest.java similarity index 100% rename from src/test/java/com/skyflow/vault/detect/FileInfoTest.java rename to v2/src/test/java/com/skyflow/vault/detect/FileInfoTest.java diff --git a/src/test/java/com/skyflow/vault/detect/ReidentifyTextTests.java b/v2/src/test/java/com/skyflow/vault/detect/ReidentifyTextTests.java similarity index 100% rename from src/test/java/com/skyflow/vault/detect/ReidentifyTextTests.java rename to v2/src/test/java/com/skyflow/vault/detect/ReidentifyTextTests.java diff --git a/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java b/v2/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java similarity index 100% rename from src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java rename to v2/src/test/java/com/skyflow/vault/tokens/DetokenizeTests.java diff --git a/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java b/v2/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java similarity index 97% rename from src/test/java/com/skyflow/vault/tokens/TokenizeTests.java rename to v2/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java index 4c279fde..debfe10a 100644 --- a/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java +++ b/v2/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java @@ -1,8 +1,7 @@ package com.skyflow.vault.tokens; import com.skyflow.Skyflow; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.Env; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; @@ -21,7 +20,7 @@ public class TokenizeTests { private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; private static String vaultID = null; private static String clusterID = null; - private static VaultConfig vaultConfig = null; + private static BaseVaultConfig vaultConfig = null; private static String token = null; private static ArrayList tokens = null; private static Skyflow skyflowClient = null; @@ -38,7 +37,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - vaultConfig = new VaultConfig(); + vaultConfig = new BaseVaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/src/test/resources/invalidPrivateKeyCredentials.json b/v2/src/test/resources/invalidPrivateKeyCredentials.json similarity index 100% rename from src/test/resources/invalidPrivateKeyCredentials.json rename to v2/src/test/resources/invalidPrivateKeyCredentials.json diff --git a/src/test/resources/invalidTokenURICredentials.json b/v2/src/test/resources/invalidTokenURICredentials.json similarity index 100% rename from src/test/resources/invalidTokenURICredentials.json rename to v2/src/test/resources/invalidTokenURICredentials.json diff --git a/src/test/resources/noClientIDCredentials.json b/v2/src/test/resources/noClientIDCredentials.json similarity index 100% rename from src/test/resources/noClientIDCredentials.json rename to v2/src/test/resources/noClientIDCredentials.json diff --git a/src/test/resources/noKeyIDCredentials.json b/v2/src/test/resources/noKeyIDCredentials.json similarity index 100% rename from src/test/resources/noKeyIDCredentials.json rename to v2/src/test/resources/noKeyIDCredentials.json diff --git a/src/test/resources/noPrivateKeyCredentials.json b/v2/src/test/resources/noPrivateKeyCredentials.json similarity index 100% rename from src/test/resources/noPrivateKeyCredentials.json rename to v2/src/test/resources/noPrivateKeyCredentials.json diff --git a/src/test/resources/noTokenURICredentials.json b/v2/src/test/resources/noTokenURICredentials.json similarity index 100% rename from src/test/resources/noTokenURICredentials.json rename to v2/src/test/resources/noTokenURICredentials.json diff --git a/src/test/resources/notJson.txt b/v2/src/test/resources/notJson.txt similarity index 100% rename from src/test/resources/notJson.txt rename to v2/src/test/resources/notJson.txt From 05c58d2927f3581f5bdf76345f9d184d3d02fb10 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 10 Jul 2026 16:50:22 +0530 Subject: [PATCH 02/28] SK-2967 add interface for skyflow --- .../src/main/java/com/skyflow/ISkyflow.java | 23 +++++++++++++ .../src/main/java/com/skyflow/Skyflow.java | 34 ++++++++++++++++++- v2/src/main/java/com/skyflow/Skyflow.java | 9 ++++- 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 common/src/main/java/com/skyflow/ISkyflow.java diff --git a/common/src/main/java/com/skyflow/ISkyflow.java b/common/src/main/java/com/skyflow/ISkyflow.java new file mode 100644 index 00000000..9d0af8e5 --- /dev/null +++ b/common/src/main/java/com/skyflow/ISkyflow.java @@ -0,0 +1,23 @@ +package com.skyflow; + +import com.skyflow.config.BaseCredentials; +import com.skyflow.config.BaseVaultConfig; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.SkyflowException; + +// Common interface — ONLY operations supported on both vault types. +public interface ISkyflow, V extends BaseVaultConfig, C extends BaseCredentials, VC> { + Self addVaultConfig(V vaultConfig) throws SkyflowException; + + Self updateVaultConfig(V vaultConfig) throws SkyflowException; + + Self removeVaultConfig(String vaultId) throws SkyflowException; + + Self updateSkyflowCredentials(C credentials) throws SkyflowException; + + Self setLogLevel(LogLevel logLevel); + + LogLevel getLogLevel(); + + VC vault() throws SkyflowException; +} diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java index ff1eff08..3608b463 100644 --- a/flowvault/src/main/java/com/skyflow/Skyflow.java +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -17,7 +17,8 @@ import java.util.LinkedHashMap; -public final class Skyflow extends BaseSkyflow { +public final class Skyflow extends BaseSkyflow + implements ISkyflow { private final SkyflowClientBuilder builder; private Skyflow(SkyflowClientBuilder builder) { @@ -35,6 +36,37 @@ public VaultConfig getVaultConfig() { return (VaultConfig) array[0]; } + @Override + public Skyflow addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + this.builder.addVaultConfig(vaultConfig); + return this; + } + + @Override + public Skyflow updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + this.builder.updateVaultConfig(vaultConfig); + return this; + } + + @Override + public Skyflow removeVaultConfig(String vaultId) throws SkyflowException { + this.builder.removeVaultConfig(vaultId); + return this; + } + + @Override + public Skyflow updateSkyflowCredentials(Credentials credentials) throws SkyflowException { + this.builder.addSkyflowCredentials(credentials); + return this; + } + + @Override + public Skyflow setLogLevel(LogLevel logLevel) { + this.builder.setLogLevel(logLevel); + return this; + } + + @Override public VaultController vault() throws SkyflowException { Object[] array = this.builder.vaultClientsMap.keySet().toArray(); if (array.length < 1) { diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index 3889b0bf..c4381e3e 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -19,7 +19,8 @@ import java.util.LinkedHashMap; -public final class Skyflow extends BaseSkyflow { +public final class Skyflow extends BaseSkyflow + implements ISkyflow { private final SkyflowClientBuilder builder; private Skyflow(SkyflowClientBuilder builder) { @@ -31,6 +32,7 @@ public static SkyflowClientBuilder builder() { return new SkyflowClientBuilder(); } + @Override public Skyflow addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { this.builder.addVaultConfig(vaultConfig); return this; @@ -40,21 +42,25 @@ public VaultConfig getVaultConfig(String vaultId) { return this.builder.vaultConfigMap.get(vaultId); } + @Override public Skyflow updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { this.builder.updateVaultConfig(vaultConfig); return this; } + @Override public Skyflow removeVaultConfig(String vaultId) throws SkyflowException { this.builder.removeVaultConfig(vaultId); return this; } + @Override public Skyflow updateSkyflowCredentials(Credentials credentials) throws SkyflowException { this.builder.addSkyflowCredentials(credentials); return this; } + @Override public Skyflow setLogLevel(LogLevel logLevel) { this.builder.setLogLevel(logLevel); return this; @@ -87,6 +93,7 @@ public Skyflow updateLogLevel(LogLevel logLevel) { return setLogLevel(logLevel); } + @Override public VaultController vault() throws SkyflowException { Object[] array = this.builder.vaultClientsMap.keySet().toArray(); if (array.length < 1) { From f92349cfca3542678d2d4f78aaf975d2ed7f79de Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Mon, 13 Jul 2026 23:57:50 +0530 Subject: [PATCH 03/28] SK-2967 move common code from v2 and flowvault --- .../java/com/skyflow/BaseVaultClient.java | 23 ++- .../src/main/java/com/skyflow/ISkyflow.java | 1 - .../java/com/skyflow/config/Credentials.java | 2 - .../java/com/skyflow/config/VaultConfig.java | 5 +- .../java/com/skyflow/enums/InterfaceName.java | 24 --- .../java/com/skyflow/errors/ErrorMessage.java | 4 +- .../java/com/skyflow/utils/BaseConstants.java | 1 - .../com/skyflow/utils/logger/LogUtil.java | 15 +- .../vault/controller/BaseVaultController.java | 21 --- flowvault/pom.xml | 3 +- .../src/main/java/com/skyflow/Skyflow.java | 11 +- .../main/java/com/skyflow/VaultClient.java | 9 +- .../java/com/skyflow/utils/Constants.java | 3 +- .../vault/controller/VaultController.java | 4 +- flowvault/src/main/resources/sdk.properties | 1 + v2/pom.xml | 10 ++ v2/src/main/java/com/skyflow/Skyflow.java | 40 ++++- v2/src/main/java/com/skyflow/VaultClient.java | 8 +- .../java/com/skyflow/config/Credentials.java | 10 -- .../java/com/skyflow/config/VaultConfig.java | 16 -- .../java/com/skyflow/errors/ErrorCode.java | 18 -- .../java/com/skyflow/errors/HttpStatus.java | 15 -- .../java/com/skyflow/utils/Constants.java | 24 +-- v2/src/main/java/com/skyflow/utils/Utils.java | 166 +----------------- .../utils/validations/Validations.java | 96 +--------- .../vault/controller/VaultController.java | 36 ++-- 26 files changed, 119 insertions(+), 447 deletions(-) rename {flowvault => common}/src/main/java/com/skyflow/config/Credentials.java (98%) rename {flowvault => common}/src/main/java/com/skyflow/config/VaultConfig.java (95%) delete mode 100644 common/src/main/java/com/skyflow/enums/InterfaceName.java delete mode 100644 common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java create mode 100644 flowvault/src/main/resources/sdk.properties delete mode 100644 v2/src/main/java/com/skyflow/config/Credentials.java delete mode 100644 v2/src/main/java/com/skyflow/config/VaultConfig.java delete mode 100644 v2/src/main/java/com/skyflow/errors/ErrorCode.java delete mode 100644 v2/src/main/java/com/skyflow/errors/HttpStatus.java diff --git a/common/src/main/java/com/skyflow/BaseVaultClient.java b/common/src/main/java/com/skyflow/BaseVaultClient.java index f0ea23d1..2ce32997 100644 --- a/common/src/main/java/com/skyflow/BaseVaultClient.java +++ b/common/src/main/java/com/skyflow/BaseVaultClient.java @@ -1,9 +1,13 @@ package com.skyflow; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.skyflow.config.BaseCredentials; +import com.skyflow.config.VaultConfig; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.serviceaccount.util.Token; import com.skyflow.utils.BaseConstants; @@ -16,10 +20,13 @@ import okhttp3.OkHttpClient; import okhttp3.Request; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; class BaseVaultClient { + protected VaultConfig vaultConfig; protected OkHttpClient sharedHttpClient; protected String currentVaultURL; protected BaseCredentials commonCredentials; @@ -27,7 +34,13 @@ class BaseVaultClient { protected String token; protected String apiKey; - public BaseVaultClient() { + protected BaseVaultClient(VaultConfig vaultConfig, BaseCredentials credentials) { + this.vaultConfig = vaultConfig; + this.commonCredentials = credentials; + } + + protected VaultConfig getVaultConfig() { + return vaultConfig; } protected OkHttpClient buildSharedHttpClient(Supplier tokenSupplier) { @@ -90,4 +103,12 @@ protected void setBearerToken(BaseCredentials vaultSpecificCredentials) throws S LogUtil.printInfoLog(InfoLogs.REUSE_BEARER_TOKEN.getLog()); } } + + protected static SkyflowException wrapApiException(int statusCode, Throwable cause, + Map> headers, + Object responseBody, ErrorLogs errorLog) { + LogUtil.printErrorLog(errorLog.getLog()); + Gson gson = new GsonBuilder().serializeNulls().create(); + return new SkyflowException(statusCode, cause, headers, gson.toJson(responseBody)); + } } diff --git a/common/src/main/java/com/skyflow/ISkyflow.java b/common/src/main/java/com/skyflow/ISkyflow.java index 9d0af8e5..f756ed2f 100644 --- a/common/src/main/java/com/skyflow/ISkyflow.java +++ b/common/src/main/java/com/skyflow/ISkyflow.java @@ -5,7 +5,6 @@ import com.skyflow.enums.LogLevel; import com.skyflow.errors.SkyflowException; -// Common interface — ONLY operations supported on both vault types. public interface ISkyflow, V extends BaseVaultConfig, C extends BaseCredentials, VC> { Self addVaultConfig(V vaultConfig) throws SkyflowException; diff --git a/flowvault/src/main/java/com/skyflow/config/Credentials.java b/common/src/main/java/com/skyflow/config/Credentials.java similarity index 98% rename from flowvault/src/main/java/com/skyflow/config/Credentials.java rename to common/src/main/java/com/skyflow/config/Credentials.java index 1e13c146..b0d6b888 100644 --- a/flowvault/src/main/java/com/skyflow/config/Credentials.java +++ b/common/src/main/java/com/skyflow/config/Credentials.java @@ -4,6 +4,4 @@ public class Credentials extends BaseCredentials { public Credentials() { super(); } - - } diff --git a/flowvault/src/main/java/com/skyflow/config/VaultConfig.java b/common/src/main/java/com/skyflow/config/VaultConfig.java similarity index 95% rename from flowvault/src/main/java/com/skyflow/config/VaultConfig.java rename to common/src/main/java/com/skyflow/config/VaultConfig.java index f90fa76c..bcb376a2 100644 --- a/flowvault/src/main/java/com/skyflow/config/VaultConfig.java +++ b/common/src/main/java/com/skyflow/config/VaultConfig.java @@ -1,7 +1,5 @@ package com.skyflow.config; -import com.skyflow.enums.Env; - public class VaultConfig extends BaseVaultConfig implements Cloneable { private Credentials credentials; @@ -19,7 +17,6 @@ public void setCredentials(Credentials credentials) { this.credentials = credentials; } - @Override public Object clone() throws CloneNotSupportedException { VaultConfig cloned = (VaultConfig) super.clone(); @@ -30,4 +27,4 @@ public Object clone() throws CloneNotSupportedException { return cloned; } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/skyflow/enums/InterfaceName.java b/common/src/main/java/com/skyflow/enums/InterfaceName.java deleted file mode 100644 index 98992f21..00000000 --- a/common/src/main/java/com/skyflow/enums/InterfaceName.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.skyflow.enums; - -public enum InterfaceName { - INSERT("insert"), - DETOKENIZE("detokenize"), - GET("get"), - UPDATE("update"), - DELETE("delete"), - QUERY("query"), - TOKENIZE("tokenize"), - FILE_UPLOAD("file upload"), - DETECT("detect"), - INVOKE_CONNECTION("invoke connection"); - - private final String interfaceName; - - InterfaceName(String interfaceName) { - this.interfaceName = interfaceName; - } - - public String getName() { - return interfaceName; - } -} diff --git a/common/src/main/java/com/skyflow/errors/ErrorMessage.java b/common/src/main/java/com/skyflow/errors/ErrorMessage.java index 169880e9..e3b5924b 100644 --- a/common/src/main/java/com/skyflow/errors/ErrorMessage.java +++ b/common/src/main/java/com/skyflow/errors/ErrorMessage.java @@ -201,10 +201,10 @@ public enum ErrorMessage { private final String message; ErrorMessage(String message) { - this.message = message.replace("%s0", SdkVersion.getSdkPrefix()); + this.message = message; } public String getMessage() { - return message; + return message.replace("%s0", SdkVersion.getSdkPrefix()); } } diff --git a/common/src/main/java/com/skyflow/utils/BaseConstants.java b/common/src/main/java/com/skyflow/utils/BaseConstants.java index 8aeb9f95..1f05fe13 100644 --- a/common/src/main/java/com/skyflow/utils/BaseConstants.java +++ b/common/src/main/java/com/skyflow/utils/BaseConstants.java @@ -21,7 +21,6 @@ public class BaseConstants { public static final String API_KEY_REGEX = "^sky-[a-zA-Z0-9]{5}-[a-fA-F0-9]{32}$"; public static final String CONTEXT_KEY_REGEX = "^[a-zA-Z0-9_]+$"; public static final String SDK_METRIC_NAME_VERSION = "sdk_name_version"; - public static final String SDK_METRIC_NAME_VERSION_PREFIX = "skyflow-java@"; public static final String SDK_METRIC_CLIENT_DEVICE_MODEL = "sdk_client_device_model"; public static final String SDK_METRIC_CLIENT_OS_DETAILS = "sdk_client_os_details"; public static final String SDK_METRIC_RUNTIME_DETAILS = "sdk_runtime_details"; diff --git a/common/src/main/java/com/skyflow/utils/logger/LogUtil.java b/common/src/main/java/com/skyflow/utils/logger/LogUtil.java index 54fc7d47..ed2b7671 100644 --- a/common/src/main/java/com/skyflow/utils/logger/LogUtil.java +++ b/common/src/main/java/com/skyflow/utils/logger/LogUtil.java @@ -8,9 +8,12 @@ public final class LogUtil { private static final Logger LOGGER = Logger.getLogger(LogUtil.class.getName()); - private static final String SDK_LOG_PREFIX = "[" + SdkVersion.getSdkPrefix() + "] "; private static boolean IS_LOGGER_SETUP_DONE = false; + private static String logPrefix() { + return "[" + SdkVersion.getSdkPrefix() + "] "; + } + synchronized public static void setupLogger(LogLevel logLevel) { IS_LOGGER_SETUP_DONE = true; LogManager.getLogManager().reset(); @@ -39,26 +42,26 @@ public synchronized String format(LogRecord logRecord) { public static void printErrorLog(String message) { if (IS_LOGGER_SETUP_DONE) - LOGGER.severe(SDK_LOG_PREFIX + message); + LOGGER.severe(logPrefix() + message); else { setupLogger(LogLevel.ERROR); - LOGGER.severe(SDK_LOG_PREFIX + message); + LOGGER.severe(logPrefix() + message); } } public static void printDebugLog(String message) { if (IS_LOGGER_SETUP_DONE) - LOGGER.config(SDK_LOG_PREFIX + message); + LOGGER.config(logPrefix() + message); } public static void printWarningLog(String message) { if (IS_LOGGER_SETUP_DONE) - LOGGER.warning(SDK_LOG_PREFIX + message); + LOGGER.warning(logPrefix() + message); } public static void printInfoLog(String message) { if (IS_LOGGER_SETUP_DONE) - LOGGER.info(SDK_LOG_PREFIX + message); + LOGGER.info(logPrefix() + message); } diff --git a/common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java b/common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java deleted file mode 100644 index d6cd31ae..00000000 --- a/common/src/main/java/com/skyflow/vault/controller/BaseVaultController.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.skyflow.vault.controller; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.skyflow.errors.SkyflowException; -import com.skyflow.logs.ErrorLogs; -import com.skyflow.utils.logger.LogUtil; - -import java.util.List; -import java.util.Map; - -public class BaseVaultController { - protected static final Gson GSON = new GsonBuilder().serializeNulls().create(); - - protected static SkyflowException wrapApiException(int statusCode, Throwable cause, - Map> headers, - Object responseBody, ErrorLogs errorLog) { - LogUtil.printErrorLog(errorLog.getLog()); - return new SkyflowException(statusCode, cause, headers, GSON.toJson(responseBody)); - } -} diff --git a/flowvault/pom.xml b/flowvault/pom.xml index 9f36f6c4..1efc6173 100644 --- a/flowvault/pom.xml +++ b/flowvault/pom.xml @@ -44,7 +44,8 @@ com.skyflow common - 1.0.1 + 1.0.0 + compile diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java index 3608b463..cb5676e4 100644 --- a/flowvault/src/main/java/com/skyflow/Skyflow.java +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -36,6 +36,10 @@ public VaultConfig getVaultConfig() { return (VaultConfig) array[0]; } + public VaultConfig getVaultConfig(String vaultId) { + return this.builder.vaultConfigMap.get(vaultId); + } + @Override public Skyflow addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { this.builder.addVaultConfig(vaultConfig); @@ -74,12 +78,15 @@ public VaultController vault() throws SkyflowException { throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); } String vaultId = (String) array[0]; + return this.vault(vaultId); + } + + public VaultController vault(String vaultId) throws SkyflowException { VaultController controller = this.builder.vaultClientsMap.get(vaultId); if (controller == null) { LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); } - return controller; } @@ -101,7 +108,7 @@ public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws Skyfl } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } - if (!this.vaultClientsMap.isEmpty()) { + if (this.vaultClientsMap.containsKey(vaultConfigCopy.getVaultId())) { LogUtil.printErrorLog(Utils.parameterizedString( ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfigCopy.getVaultId() )); diff --git a/flowvault/src/main/java/com/skyflow/VaultClient.java b/flowvault/src/main/java/com/skyflow/VaultClient.java index 00a3d57d..e7d395a7 100644 --- a/flowvault/src/main/java/com/skyflow/VaultClient.java +++ b/flowvault/src/main/java/com/skyflow/VaultClient.java @@ -8,15 +8,12 @@ import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; import com.skyflow.utils.Utils; - public class VaultClient extends BaseVaultClient { - private final VaultConfig vaultConfig; private final ApiClientBuilder apiClientBuilder; private ApiClient apiClient; protected VaultClient(VaultConfig vaultConfig, Credentials credentials) throws SkyflowException { - this.vaultConfig = vaultConfig; - this.commonCredentials = credentials; + super(vaultConfig, credentials); this.apiClientBuilder = new ApiClientBuilder(); this.apiClient = null; updateVaultURL(); @@ -26,10 +23,6 @@ protected FlowserviceClient getRecordsApi() { return this.apiClient.flowservice(); } - protected VaultConfig getVaultConfig() { - return vaultConfig; - } - protected void setCommonCredentials(Credentials commonCredentials) throws SkyflowException { this.commonCredentials = commonCredentials; super.prioritiseCredentials(this.vaultConfig.getCredentials()); diff --git a/flowvault/src/main/java/com/skyflow/utils/Constants.java b/flowvault/src/main/java/com/skyflow/utils/Constants.java index ff5f9eb2..983e82b3 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Constants.java +++ b/flowvault/src/main/java/com/skyflow/utils/Constants.java @@ -5,10 +5,11 @@ import java.util.Properties; public final class Constants extends BaseConstants { - public static final String SDK_NAME = "Skyflow Java SDK "; + public static final String SDK_NAME = "Skyflow Java SDK"; public static final String SDK_VERSION; public static final String VAULT_DOMAIN = ".skyvault."; public static final String SDK_PREFIX; + public static final String SDK_METRIC_NAME_VERSION_PREFIX = "skyflow-flowvault-java@"; public static final Integer INSERT_BATCH_SIZE = 50; public static final Integer MAX_INSERT_BATCH_SIZE = 1000; public static final Integer INSERT_CONCURRENCY_LIMIT = 1; diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java index 62f8f2cb..6afd5cdb 100644 --- a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -13,7 +13,8 @@ import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertResponse; -public final class VaultController extends VaultClient implements IVaultController{ +public final class VaultController extends VaultClient + implements IVaultController { private static final Gson gson = new GsonBuilder().serializeNulls().create(); private JsonObject metrics = Utils.getMetrics(); @@ -21,7 +22,6 @@ public VaultController(VaultConfig vaultConfig, Credentials credentials) throws super(vaultConfig, credentials); } - @Override public InsertResponse insert(InsertRequest request) throws SkyflowException { return null; diff --git a/flowvault/src/main/resources/sdk.properties b/flowvault/src/main/resources/sdk.properties new file mode 100644 index 00000000..a33c65cd --- /dev/null +++ b/flowvault/src/main/resources/sdk.properties @@ -0,0 +1 @@ +sdk.version=${sdk.version} diff --git a/v2/pom.xml b/v2/pom.xml index cf5a35b6..b2145ec6 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -18,6 +18,7 @@ 8 8 UTF-8 + ${project.version} @@ -28,4 +29,13 @@ + + + + + src/main/resources + true + + + \ No newline at end of file diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index c4381e3e..d36c24e3 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -10,6 +10,8 @@ import com.skyflow.errors.SkyflowException; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; +import com.skyflow.utils.Constants; +import com.skyflow.utils.SdkVersion; import com.skyflow.utils.Utils; import com.skyflow.utils.logger.LogUtil; import com.skyflow.utils.validations.Validations; @@ -29,6 +31,7 @@ private Skyflow(SkyflowClientBuilder builder) { } public static SkyflowClientBuilder builder() { + SdkVersion.setSdkPrefix(Constants.SDK_PREFIX); return new SkyflowClientBuilder(); } @@ -171,20 +174,26 @@ public SkyflowClientBuilder() { public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); Validations.validateVaultConfig(vaultConfig); - if (this.vaultClientsMap.containsKey(vaultConfig.getVaultId())) { + VaultConfig vaultConfigCopy; + try { + vaultConfigCopy = (VaultConfig) vaultConfig.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + if (this.vaultClientsMap.containsKey(vaultConfigCopy.getVaultId())) { LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfig.getVaultId() + ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfigCopy.getVaultId() )); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdAlreadyInConfigList.getMessage()); } else { - this.vaultConfigMap.put(vaultConfig.getVaultId(), vaultConfig); - this.vaultClientsMap.put(vaultConfig.getVaultId(), new VaultController(vaultConfig, this.skyflowCredentials)); - this.detectClientsMap.put(vaultConfig.getVaultId(), new DetectController(vaultConfig, this.skyflowCredentials)); + this.vaultConfigMap.put(vaultConfigCopy.getVaultId(), vaultConfigCopy); + this.vaultClientsMap.put(vaultConfigCopy.getVaultId(), new VaultController(vaultConfigCopy, this.skyflowCredentials)); + this.detectClientsMap.put(vaultConfigCopy.getVaultId(), new DetectController(vaultConfigCopy, this.skyflowCredentials)); LogUtil.printInfoLog(Utils.parameterizedString( - InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfig.getVaultId())); + InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfigCopy.getVaultId())); LogUtil.printInfoLog(Utils.parameterizedString( - InfoLogs.DETECT_CONTROLLER_INITIALIZED.getLog(), vaultConfig.getVaultId())); + InfoLogs.DETECT_CONTROLLER_INITIALIZED.getLog(), vaultConfigCopy.getVaultId())); } return this; } @@ -266,7 +275,13 @@ public SkyflowClientBuilder removeConnectionConfig(String connectionId) throws S public SkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { Validations.validateCredentials(credentials); - this.skyflowCredentials = credentials; + Credentials credentialsCopy; + try { + credentialsCopy = (Credentials) credentials.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + this.skyflowCredentials = credentialsCopy; for (VaultController vault : this.vaultClientsMap.values()) { vault.setCommonCredentials(this.skyflowCredentials); } @@ -293,7 +308,14 @@ private VaultConfig findAndUpdateVaultConfig(VaultConfig vaultConfig) { VaultConfig previousConfig = this.vaultConfigMap.get(vaultConfig.getVaultId()); Env env = vaultConfig.getEnv() != null ? vaultConfig.getEnv() : previousConfig.getEnv(); String clusterId = vaultConfig.getClusterId() != null ? vaultConfig.getClusterId() : previousConfig.getClusterId(); - Credentials credentials = vaultConfig.getCredentials() != null ? vaultConfig.getCredentials() : previousConfig.getCredentials(); + Credentials credentials = previousConfig.getCredentials(); + if (vaultConfig.getCredentials() != null) { + try { + credentials = (Credentials) vaultConfig.getCredentials().clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } previousConfig.setEnv(env); previousConfig.setClusterId(clusterId); previousConfig.setCredentials(credentials); diff --git a/v2/src/main/java/com/skyflow/VaultClient.java b/v2/src/main/java/com/skyflow/VaultClient.java index ff8088eb..ef6381b5 100644 --- a/v2/src/main/java/com/skyflow/VaultClient.java +++ b/v2/src/main/java/com/skyflow/VaultClient.java @@ -45,13 +45,11 @@ public class VaultClient extends BaseVaultClient { - private final VaultConfig vaultConfig; private final ApiClientBuilder apiClientBuilder; private ApiClient apiClient; protected VaultClient(VaultConfig vaultConfig, Credentials credentials) { - this.vaultConfig = vaultConfig; - this.commonCredentials = credentials; + super(vaultConfig, credentials); this.apiClientBuilder = new ApiClientBuilder(); this.apiClient = null; updateVaultURL(); @@ -77,10 +75,6 @@ protected QueryClient getQueryApi() { return this.apiClient.query(); } - protected VaultConfig getVaultConfig() { - return vaultConfig; - } - protected void setCommonCredentials(Credentials commonCredentials) throws SkyflowException { this.commonCredentials = commonCredentials; super.prioritiseCredentials(this.vaultConfig.getCredentials()); diff --git a/v2/src/main/java/com/skyflow/config/Credentials.java b/v2/src/main/java/com/skyflow/config/Credentials.java deleted file mode 100644 index 5d1a7859..00000000 --- a/v2/src/main/java/com/skyflow/config/Credentials.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.skyflow.config; - -import java.util.Map; - -public class Credentials extends BaseCredentials { - - public Credentials() { - super(); - } -} diff --git a/v2/src/main/java/com/skyflow/config/VaultConfig.java b/v2/src/main/java/com/skyflow/config/VaultConfig.java deleted file mode 100644 index 36d86668..00000000 --- a/v2/src/main/java/com/skyflow/config/VaultConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.skyflow.config; - -public class VaultConfig extends BaseVaultConfig { - Credentials credentials; - public VaultConfig() { - super(); - } - - public Credentials getCredentials() { - return credentials; - } - - public void setCredentials(Credentials credentials) { - this.credentials = credentials; - } -} diff --git a/v2/src/main/java/com/skyflow/errors/ErrorCode.java b/v2/src/main/java/com/skyflow/errors/ErrorCode.java deleted file mode 100644 index 943913c6..00000000 --- a/v2/src/main/java/com/skyflow/errors/ErrorCode.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.skyflow.errors; - -public enum ErrorCode { - INVALID_INPUT(400), - INVALID_INDEX(404), - SERVER_ERROR(500), - PARTIAL_SUCCESS(500); - - private final int code; - - ErrorCode(int code) { - this.code = code; - } - - public int getCode() { - return code; - } -} diff --git a/v2/src/main/java/com/skyflow/errors/HttpStatus.java b/v2/src/main/java/com/skyflow/errors/HttpStatus.java deleted file mode 100644 index 2cdadbb0..00000000 --- a/v2/src/main/java/com/skyflow/errors/HttpStatus.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.skyflow.errors; - -public enum HttpStatus { - BAD_REQUEST("Bad Request"); - - private final String httpStatus; - - HttpStatus(String httpStatus) { - this.httpStatus = httpStatus; - } - - public String getHttpStatus() { - return httpStatus; - } -} diff --git a/v2/src/main/java/com/skyflow/utils/Constants.java b/v2/src/main/java/com/skyflow/utils/Constants.java index aa3a3f14..2ca105d5 100644 --- a/v2/src/main/java/com/skyflow/utils/Constants.java +++ b/v2/src/main/java/com/skyflow/utils/Constants.java @@ -4,35 +4,13 @@ import java.io.InputStream; import java.util.Properties; -public final class Constants { - public static final String SECURE_PROTOCOL = "https://"; - public static final String DEV_DOMAIN = ".vault.skyflowapis.dev"; - public static final String STAGE_DOMAIN = ".vault.skyflowapis.tech"; - public static final String SANDBOX_DOMAIN = ".vault.skyflowapis-preview.com"; - public static final String PROD_DOMAIN = ".vault.skyflowapis.com"; - public static final String PKCS8_PRIVATE_HEADER = "-----BEGIN PRIVATE KEY-----"; - public static final String PKCS8_PRIVATE_FOOTER = "-----END PRIVATE KEY-----"; - public static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer"; - public static final String SIGNED_DATA_TOKEN_PREFIX = "signed_token_"; - public static final String ORDER_ASCENDING = "ASCENDING"; - public static final String API_KEY_REGEX = "^sky-[a-zA-Z0-9]{5}-[a-fA-F0-9]{32}$"; - public static final String CONTEXT_KEY_REGEX = "^[a-zA-Z0-9_]+$"; - public static final String ENV_CREDENTIALS_KEY_NAME = "SKYFLOW_CREDENTIALS"; +public final class Constants extends BaseConstants { public static final String SDK_NAME = "Skyflow Java SDK"; public static final String DEFAULT_SDK_VERSION = "v2"; public static final String SDK_VERSION; public static final String SDK_PREFIX; - public static final String SDK_METRIC_NAME_VERSION = "sdk_name_version"; public static final String SDK_METRIC_NAME_VERSION_PREFIX = "skyflow-java@"; - public static final String SDK_METRIC_CLIENT_DEVICE_MODEL = "sdk_client_device_model"; - public static final String SDK_METRIC_CLIENT_OS_DETAILS = "sdk_client_os_details"; - public static final String SDK_METRIC_RUNTIME_DETAILS = "sdk_runtime_details"; - public static final String SDK_METRIC_RUNTIME_DETAILS_PREFIX = "Java@"; - public static final String SDK_AUTH_HEADER_KEY = "x-skyflow-authorization"; - public static final String SDK_METRICS_HEADER_KEY = "sky-metadata"; - public static final String REQUEST_ID_HEADER_KEY = "x-request-id"; public static final String PROCESSED_FILE_NAME_PREFIX = "processed-"; - public static final String ERROR_FROM_CLIENT_HEADER_KEY = "error-from-client"; public static final String DEIDENTIFIED_FILE_PREFIX = "deidentified"; public static final String HTTPS_PROTOCOL = "https"; public static final String CURLY_PLACEHOLDER = "{%s}"; diff --git a/v2/src/main/java/com/skyflow/utils/Utils.java b/v2/src/main/java/com/skyflow/utils/Utils.java index ae5854cd..b5f81769 100644 --- a/v2/src/main/java/com/skyflow/utils/Utils.java +++ b/v2/src/main/java/com/skyflow/utils/Utils.java @@ -2,114 +2,15 @@ import com.google.gson.JsonObject; import com.skyflow.config.ConnectionConfig; -import com.skyflow.config.Credentials; import com.skyflow.enums.Env; -import com.skyflow.errors.ErrorCode; -import com.skyflow.errors.ErrorMessage; -import com.skyflow.errors.SkyflowException; -import com.skyflow.logs.ErrorLogs; -import com.skyflow.logs.InfoLogs; -import com.skyflow.serviceaccount.util.BearerToken; -import com.skyflow.utils.logger.LogUtil; import com.skyflow.vault.connection.InvokeConnectionRequest; -import org.apache.commons.codec.binary.Base64; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; import java.util.HashMap; import java.util.Map; -public final class Utils { +public final class Utils extends BaseUtils { public static String getVaultURL(String clusterId, Env env) { - StringBuilder sb = new StringBuilder(Constants.SECURE_PROTOCOL); - sb.append(clusterId); - switch (env) { - case DEV: - sb.append(Constants.DEV_DOMAIN); - break; - case STAGE: - sb.append(Constants.STAGE_DOMAIN); - break; - case SANDBOX: - sb.append(Constants.SANDBOX_DOMAIN); - break; - case PROD: - default: - sb.append(Constants.PROD_DOMAIN); - break; - } - return sb.toString(); - } - - @SuppressWarnings("unchecked") - public static String generateBearerToken(Credentials credentials) throws SkyflowException { - if (credentials.getPath() != null) { - BearerToken.BearerTokenBuilder builder = BearerToken.builder() - .setCredentials(new File(credentials.getPath())) - .setRoles(credentials.getRoles()); - Object ctx = credentials.getContext(); - if (ctx instanceof String) { - builder.setCtx((String) ctx); - } else if (ctx instanceof Map) { - builder.setCtx((Map) ctx); - } - return builder.build().getBearerToken(); - } else if (credentials.getCredentialsString() != null) { - BearerToken.BearerTokenBuilder builder = BearerToken.builder() - .setCredentials(credentials.getCredentialsString()) - .setRoles(credentials.getRoles()); - Object ctx = credentials.getContext(); - if (ctx instanceof String) { - builder.setCtx((String) ctx); - } else if (ctx instanceof Map) { - builder.setCtx((Map) ctx); - } - return builder.build().getBearerToken(); - } else { - return credentials.getToken(); - } - } - - public static PrivateKey getPrivateKeyFromPem(String pemKey) throws SkyflowException { - @SuppressWarnings("checkstyle:LocalVariableName") - String PKCS8PrivateHeader = Constants.PKCS8_PRIVATE_HEADER; - @SuppressWarnings("checkstyle:LocalVariableName") - String PKCS8PrivateFooter = Constants.PKCS8_PRIVATE_FOOTER; - - String privateKeyContent = pemKey; - PrivateKey privateKey = null; - - if (pemKey.contains(PKCS8PrivateHeader)) { - privateKeyContent = privateKeyContent.replace(PKCS8PrivateHeader, ""); - privateKeyContent = privateKeyContent.replace(PKCS8PrivateFooter, ""); - privateKeyContent = privateKeyContent.replace("\n", ""); - privateKeyContent = privateKeyContent.replace("\r\n", ""); - privateKey = parsePkcs8PrivateKey(Base64.decodeBase64(privateKeyContent)); - } else { - LogUtil.printErrorLog(ErrorLogs.JWT_INVALID_FORMAT.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.JwtInvalidFormat.getMessage()); - } - return privateKey; - } - - public static String getBaseURL(String url) throws MalformedURLException { - URL parsedUrl = new URL(url); - String protocol = parsedUrl.getProtocol(); - String host = parsedUrl.getHost(); - return String.format("%s://%s", protocol, host); - } - - public static String parameterizedString(String base, String... args) { - for (int index = 0; index < args.length; index++) { - base = base.replace("%s" + (index + 1), args[index]); - } - return base; + return getVaultURL(clusterId, env, BaseConstants.V2_VAULT_DOMAIN); } public static String constructConnectionURL(ConnectionConfig config, InvokeConnectionRequest invokeConnectionRequest) { @@ -147,67 +48,8 @@ public static Map constructConnectionHeadersMap(Map roles = credentials.getRoles(); - - if (path != null) nonNullMembers++; - if (credentialsString != null) nonNullMembers++; - if (token != null) nonNullMembers++; - if (apiKey != null) nonNullMembers++; - - if (nonNullMembers > 1) { - LogUtil.printErrorLog(ErrorLogs.MULTIPLE_TOKEN_GENERATION_MEANS_PASSED.getLog()); - throw new SkyflowException( - ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MultipleTokenGenerationMeansPassed.getMessage() - ); - } else if (nonNullMembers < 1) { - LogUtil.printErrorLog(ErrorLogs.NO_TOKEN_GENERATION_MEANS_PASSED.getLog()); - throw new SkyflowException( - ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NoTokenGenerationMeansPassed.getMessage() - ); - } else if (path != null && path.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_PATH.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialFilePath.getMessage()); - } else if (credentialsString != null && credentialsString.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_CREDENTIALS_STRING.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentialsString.getMessage()); - } else if (token != null && token.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_TOKEN_VALUE.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyToken.getMessage()); - } else if (apiKey != null) { - if (apiKey.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_API_KEY_VALUE.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyApikey.getMessage()); - } else { - Pattern pattern = Pattern.compile(Constants.API_KEY_REGEX); - Matcher matcher = pattern.matcher(apiKey); - if (!matcher.matches()) { - LogUtil.printErrorLog(ErrorLogs.INVALID_API_KEY.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidApikey.getMessage()); - } - } - } else if (roles != null) { - if (roles.isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_ROLES.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoles.getMessage()); - } else { - for (int index = 0; index < roles.size(); index++) { - String role = roles.get(index); - if (role == null || role.trim().isEmpty()) { - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.EMPTY_OR_NULL_ROLE_IN_ROLES.getLog(), Integer.toString(index) - )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRoleInRoles.getMessage()); - } - } - } - } - if (context != null) { - if (context instanceof String) { - String ctxStr = (String) context; - if (ctxStr.trim().isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); - } - } else if (context instanceof Map) { - Map ctxMap = (Map) context; - if (ctxMap.isEmpty()) { - LogUtil.printErrorLog(ErrorLogs.EMPTY_OR_NULL_CONTEXT.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyContext.getMessage()); - } - Pattern ctxKeyPattern = Pattern.compile(Constants.CONTEXT_KEY_REGEX); - for (Object key : ctxMap.keySet()) { - if (key == null || !ctxKeyPattern.matcher(key.toString()).matches()) { - String keyStr = key == null ? "null" : key.toString(); - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.INVALID_CONTEXT_MAP_KEY.getLog(), keyStr)); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), - Utils.parameterizedString(ErrorMessage.InvalidContextMapKey.getMessage(), keyStr)); - } - } - } else { - LogUtil.printErrorLog(ErrorLogs.INVALID_CONTEXT_TYPE.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidContextType.getMessage()); - } - } - } public static void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { String vaultId = vaultConfig.getVaultId(); diff --git a/v2/src/main/java/com/skyflow/vault/controller/VaultController.java b/v2/src/main/java/com/skyflow/vault/controller/VaultController.java index 2f74a584..1d82ac12 100644 --- a/v2/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/v2/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -79,6 +79,10 @@ public final class VaultController extends VaultClient private static final Gson GSON = new GsonBuilder().serializeNulls().create(); private static final JsonObject SKY_METADATA = Utils.getMetrics(); + private static RequestOptions buildRequestOptions() { + return RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + } + public VaultController(VaultConfig vaultConfig, Credentials credentials) { super(vaultConfig, credentials); } @@ -197,7 +201,7 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio setBearerToken(); if (continueOnError) { RecordServiceBatchOperationBody insertBody = super.getBatchInsertRequestBody(insertRequest); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); batchInsertResult = super.getRecordsApi().withRawResponse().recordServiceBatchOperation(super.getVaultConfig().getVaultId(), insertBody, requestOptions); LogUtil.printInfoLog(InfoLogs.INSERT_REQUEST_RESOLVED.getLog()); Optional>> records = batchInsertResult.body().getResponses(); @@ -232,7 +236,7 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio } } } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.INSERT_RECORDS_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.INSERT_RECORDS_REJECTED); } LogUtil.printInfoLog(InfoLogs.INSERT_SUCCESS.getLog()); if (insertedFields.isEmpty()) { @@ -254,7 +258,7 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws Validations.validateDetokenizeRequest(detokenizeRequest); setBearerToken(); V1DetokenizePayload payload = super.getDetokenizePayload(detokenizeRequest); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); result = super.getTokensApi().withRawResponse().recordServiceDetokenize(super.getVaultConfig().getVaultId(), payload, requestOptions); LogUtil.printInfoLog(InfoLogs.DETOKENIZE_REQUEST_RESOLVED.getLog()); Map> responseHeaders = result.headers(); @@ -275,7 +279,7 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws } } } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.DETOKENIZE_REQUEST_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.DETOKENIZE_REQUEST_REJECTED); } if (!errorRecords.isEmpty()) { @@ -315,7 +319,7 @@ public GetResponse get(GetRequest getRequest) throws SkyflowException { .orderBy(RecordServiceBulkGetRecordRequestOrderBy.valueOf(getRequest.getOrderBy())) .build(); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); result = super.getRecordsApi().recordServiceBulkGetRecord( super.getVaultConfig().getVaultId(), getRequest.getTable(), @@ -330,7 +334,7 @@ public GetResponse get(GetRequest getRequest) throws SkyflowException { } } } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.GET_REQUEST_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.GET_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.GET_SUCCESS.getLog()); return new GetResponse(data, null); @@ -346,7 +350,7 @@ public UpdateResponse update(UpdateRequest updateRequest) throws SkyflowExceptio Validations.validateUpdateRequest(updateRequest); setBearerToken(); RecordServiceUpdateRecordBody updateBody = super.getUpdateRequestBody(updateRequest); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); result = super.getRecordsApi().recordServiceUpdateRecord( super.getVaultConfig().getVaultId(), updateRequest.getTable(), @@ -358,7 +362,7 @@ public UpdateResponse update(UpdateRequest updateRequest) throws SkyflowExceptio skyflowId = String.valueOf(result.getSkyflowId()); tokensMap = getFormattedUpdateRecord(result); } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.UPDATE_REQUEST_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.UPDATE_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.UPDATE_SUCCESS.getLog()); return new UpdateResponse(skyflowId, tokensMap); @@ -374,12 +378,12 @@ public DeleteResponse delete(DeleteRequest deleteRequest) throws SkyflowExceptio RecordServiceBulkDeleteRecordBody deleteBody = RecordServiceBulkDeleteRecordBody.builder().skyflowIds(deleteRequest.getIds()) .build(); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); result = super.getRecordsApi().recordServiceBulkDeleteRecord( super.getVaultConfig().getVaultId(), deleteRequest.getTable(), deleteBody, requestOptions); LogUtil.printInfoLog(InfoLogs.DELETE_REQUEST_RESOLVED.getLog()); } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.DELETE_REQUEST_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.DELETE_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.DELETE_SUCCESS.getLog()); return new DeleteResponse(result.getRecordIdResponse().orElse(Collections.emptyList())); @@ -393,7 +397,7 @@ public QueryResponse query(QueryRequest queryRequest) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.VALIDATING_QUERY_REQUEST.getLog()); Validations.validateQueryRequest(queryRequest); setBearerToken(); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); result = super.getQueryApi().queryServiceExecuteQuery( super.getVaultConfig().getVaultId(), QueryServiceExecuteQueryBody.builder().query(queryRequest.getQuery()).build(), @@ -407,7 +411,7 @@ public QueryResponse query(QueryRequest queryRequest) throws SkyflowException { } } } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.QUERY_REQUEST_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.QUERY_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.QUERY_SUCCESS.getLog()); return new QueryResponse(fields); @@ -422,7 +426,7 @@ public TokenizeResponse tokenize(TokenizeRequest tokenizeRequest) throws Skyflow Validations.validateTokenizeRequest(tokenizeRequest); setBearerToken(); V1TokenizePayload payload = super.getTokenizePayload(tokenizeRequest); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); result = super.getTokensApi().recordServiceTokenize(super.getVaultConfig().getVaultId(), payload, requestOptions); LogUtil.printInfoLog(InfoLogs.TOKENIZE_REQUEST_RESOLVED.getLog()); if (result != null && result.getRecords().isPresent() && !result.getRecords().get().isEmpty()) { @@ -433,7 +437,7 @@ public TokenizeResponse tokenize(TokenizeRequest tokenizeRequest) throws Skyflow } } } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.TOKENIZE_REQUEST_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.TOKENIZE_REQUEST_REJECTED); } LogUtil.printInfoLog(InfoLogs.TOKENIZE_SUCCESS.getLog()); return new TokenizeResponse(list); @@ -456,7 +460,7 @@ public FileUploadResponse uploadFile(FileUploadRequest fileUploadRequest) throws .returnFileMetadata(false) .build(); - RequestOptions requestOptions = RequestOptions.builder().addHeader(Constants.SDK_METRICS_HEADER_KEY, SKY_METADATA.toString()).build(); + RequestOptions requestOptions = buildRequestOptions(); UploadFileV2Response uploadFileV2Response = super.getRecordsApi().uploadFileV2( super.getVaultConfig().getVaultId(), file, @@ -470,7 +474,7 @@ public FileUploadResponse uploadFile(FileUploadRequest fileUploadRequest) throws ); } catch (ApiClientApiException e) { - throw BaseVaultController.wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.UPLOAD_FILE_REQUEST_REJECTED); + throw wrapApiException(e.statusCode(), e, e.headers(), e.body(), ErrorLogs.UPLOAD_FILE_REQUEST_REJECTED); } catch (IOException e) { LogUtil.printErrorLog(ErrorLogs.UPLOAD_FILE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.getMessage(), e); From 6f2f55c9a99bf74fd8bfb00ce5dc46e640b95dcd Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Tue, 14 Jul 2026 00:27:06 +0530 Subject: [PATCH 04/28] SK-2967 fix tests --- v2/pom.xml | 10 ++++ .../test/java/com/skyflow/SkyflowTests.java | 57 ++++++++++--------- .../controller/DetectControllerTests.java | 9 +-- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/v2/pom.xml b/v2/pom.xml index b2145ec6..b35a9552 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -37,5 +37,15 @@ true + + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + + \ No newline at end of file diff --git a/v2/src/test/java/com/skyflow/SkyflowTests.java b/v2/src/test/java/com/skyflow/SkyflowTests.java index 360daddd..f73b5bb0 100644 --- a/v2/src/test/java/com/skyflow/SkyflowTests.java +++ b/v2/src/test/java/com/skyflow/SkyflowTests.java @@ -1,6 +1,7 @@ package com.skyflow; -import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; import com.skyflow.config.ConnectionConfig; import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; @@ -60,7 +61,7 @@ public static void setup() { @Test public void testAddingInvalidVaultConfigInSkyflowBuilder() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(""); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -75,7 +76,7 @@ public void testAddingInvalidVaultConfigInSkyflowBuilder() { @Test public void testAddingInvalidVaultConfigInSkyflowClient() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(""); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -91,7 +92,7 @@ public void testAddingInvalidVaultConfigInSkyflowClient() { @Test public void testAddingValidVaultConfigInSkyflowClient() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -105,7 +106,7 @@ public void testAddingValidVaultConfigInSkyflowClient() { @Test public void testAddingExistingVaultConfigInSkyflowClient() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -121,7 +122,7 @@ public void testAddingExistingVaultConfigInSkyflowClient() { @Test public void testUpdatingNonExistentVaultConfigInSkyflowBuilder() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -136,7 +137,7 @@ public void testUpdatingNonExistentVaultConfigInSkyflowBuilder() { @Test public void testUpdatingNonExistentVaultConfigInSkyflowClient() { try { - BaseVaultConfig config = new VaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -154,7 +155,7 @@ public void testUpdatingNonExistentVaultConfigInSkyflowClient() { @Test public void testUpdatingValidVaultConfigInSkyflowClient() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -176,7 +177,7 @@ public void testUpdatingValidVaultConfigInSkyflowClient() { @Test public void testUpdateVaultConfigNullCredentialsFallsBackToPrevious() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -188,7 +189,7 @@ public void testUpdateVaultConfigNullCredentialsFallsBackToPrevious() { Skyflow skyflowClient = Skyflow.builder().addVaultConfig(config).build(); // Update with null credentials — should retain previous credentials value - BaseVaultConfig partialUpdate = new BaseVaultConfig(); + VaultConfig partialUpdate = new VaultConfig(); partialUpdate.setVaultId(vaultID); partialUpdate.setClusterId(clusterID); skyflowClient.updateVaultConfig(partialUpdate); @@ -212,7 +213,7 @@ public void testRemovingNonExistentVaultConfigInSkyflowBuilder() { @Test public void testRemovingNonExistentVaultConfigInSkyflowClient() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -239,7 +240,7 @@ public void testRemovingValidVaultConfigInSkyflowClient() { public void testGettingNonExistentVaultConfigInSkyflowClient() { try { Skyflow skyflowClient = Skyflow.builder().build(); - BaseVaultConfig config = skyflowClient.getVaultConfig(vaultID); + VaultConfig config = skyflowClient.getVaultConfig(vaultID); Assert.assertNull(config); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); @@ -261,12 +262,12 @@ public void testGettingAlreadyRemovedVaultFromEmptyConfigs() { @Test public void testGettingAlreadyRemovedVaultFromNonEmptyConfigs() { try { - BaseVaultConfig primaryConfig = new BaseVaultConfig(); + VaultConfig primaryConfig = new VaultConfig(); primaryConfig.setVaultId(vaultID); primaryConfig.setClusterId(clusterID); primaryConfig.setEnv(Env.SANDBOX); - BaseVaultConfig secondaryConfig = new BaseVaultConfig(); + VaultConfig secondaryConfig = new VaultConfig(); secondaryConfig.setVaultId(vaultID + "123"); secondaryConfig.setClusterId(clusterID); secondaryConfig.setEnv(Env.SANDBOX); @@ -475,7 +476,7 @@ public void testAddingInvalidSkyflowCredentialsInSkyflowBuilder() { @Test public void testUpdatingValidSkyflowCredentialsInSkyflowClient() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); @@ -574,7 +575,7 @@ public void testVaultMethodWithNoConfig() { @Test public void testVaultMethodWithValidConfig() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -589,7 +590,7 @@ public void testVaultMethodWithValidConfig() { @Test public void testVaultMethodWithInvalidVaultId() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -658,7 +659,7 @@ public void testDetectMethodWithNoConfig() { @Test public void testDetectMethodWithValidConfig() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -673,7 +674,7 @@ public void testDetectMethodWithValidConfig() { @Test public void testDetectMethodWithInvalidVaultId() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.SANDBOX); @@ -689,7 +690,7 @@ public void testDetectMethodWithInvalidVaultId() { @Test public void testUpdateVaultConfig_withNewClusterIdAndCredentials_updatesAllFields() { try { - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.DEV); @@ -702,7 +703,7 @@ public void testUpdateVaultConfig_withNewClusterIdAndCredentials_updatesAllField // the non-null (true) branches for all three ternaries in findAndUpdateVaultConfig Credentials newCreds = new Credentials(); newCreds.setToken("updated-token-value"); - BaseVaultConfig update = new BaseVaultConfig(); + VaultConfig update = new VaultConfig(); update.setVaultId(vaultID); update.setClusterId(newClusterID); update.setEnv(Env.PROD); @@ -751,14 +752,14 @@ public void testUpdateVaultConfig_withNullEnv_fallsBackToPreviousEnv() { try { Credentials creds = new Credentials(); creds.setToken(token); - BaseVaultConfig initial = new BaseVaultConfig(); + VaultConfig initial = new VaultConfig(); initial.setVaultId(vaultID); initial.setClusterId(clusterID); initial.setEnv(Env.SANDBOX); initial.setCredentials(creds); Skyflow skyflowClient = Skyflow.builder().addVaultConfig(initial).build(); - BaseVaultConfig updateWithNullEnv = new BaseVaultConfig() { + VaultConfig updateWithNullEnv = new VaultConfig() { @Override public Env getEnv() { return null; } }; updateWithNullEnv.setVaultId(vaultID); @@ -781,7 +782,7 @@ public void testFindAndUpdateVaultConfig_withNullClusterId_fallsBackToPreviousCl try { Credentials creds = new Credentials(); creds.setToken(token); - BaseVaultConfig initial = new BaseVaultConfig(); + VaultConfig initial = new VaultConfig(); initial.setVaultId(vaultID); initial.setClusterId(clusterID); initial.setEnv(Env.DEV); @@ -792,17 +793,17 @@ public void testFindAndUpdateVaultConfig_withNullClusterId_fallsBackToPreviousCl builderField.setAccessible(true); Object builder = builderField.get(skyflowClient); - BaseVaultConfig nullClusterConfig = new BaseVaultConfig(); + VaultConfig nullClusterConfig = new VaultConfig(); nullClusterConfig.setVaultId(vaultID); // Override clusterId field to null via reflection (setter enforces non-null) - java.lang.reflect.Field clusterIdField = BaseVaultConfig.class.getDeclaredField("clusterId"); + java.lang.reflect.Field clusterIdField = VaultConfig.class.getDeclaredField("clusterId"); clusterIdField.setAccessible(true); clusterIdField.set(nullClusterConfig, null); java.lang.reflect.Method method = builder.getClass().getDeclaredMethod( - "findAndUpdateVaultConfig", BaseVaultConfig.class); + "findAndUpdateVaultConfig", VaultConfig.class); method.setAccessible(true); - BaseVaultConfig result = (BaseVaultConfig) method.invoke(builder, nullClusterConfig); + VaultConfig result = (VaultConfig) method.invoke(builder, nullClusterConfig); Assert.assertEquals(clusterID, result.getClusterId()); } catch (SkyflowException e) { diff --git a/v2/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java b/v2/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java index 83ad9d5c..52bb2be4 100644 --- a/v2/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java +++ b/v2/src/test/java/com/skyflow/vault/controller/DetectControllerTests.java @@ -2,7 +2,8 @@ import com.skyflow.Skyflow; import com.skyflow.VaultClient; -import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; import com.skyflow.enums.DetectEntities; import com.skyflow.enums.Env; import com.skyflow.enums.LogLevel; @@ -55,7 +56,7 @@ public class DetectControllerTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; private static String vaultID = null; private static String clusterID = null; - private static BaseVaultConfig vaultConfig = null; + private static VaultConfig vaultConfig = null; private static Skyflow skyflowClient = null; @BeforeClass @@ -66,7 +67,7 @@ public static void setup() throws SkyflowException { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - vaultConfig = new BaseVaultConfig(); + vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); @@ -84,7 +85,7 @@ private static DetectController createDetectControllerWithMock(ApiClient mockApi Credentials creds = new Credentials(); creds.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); - BaseVaultConfig config = new BaseVaultConfig(); + VaultConfig config = new VaultConfig(); config.setVaultId(vaultID); config.setClusterId(clusterID); config.setEnv(Env.DEV); From 7356089255f6672535d092373ce1931d7147ba3f Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Tue, 14 Jul 2026 14:34:40 +0530 Subject: [PATCH 05/28] SK-2967 add base insert request and refactor the base skyflow --- .../main/java/com/skyflow/BaseSkyflow.java | 171 ++++++++++++- .../src/main/java/com/skyflow/ISkyflow.java | 4 +- .../skyflow/vault/data/BaseInsertRequest.java | 23 +- .../src/main/java/com/skyflow/Skyflow.java | 149 +++-------- .../com/skyflow/vault/data/InsertOptions.java | 30 +++ .../com/skyflow/vault/data/InsertRecord.java | 68 +++++ .../com/skyflow/vault/data/InsertRequest.java | 66 ++++- .../skyflow/vault/data/RequestContext.java | 26 ++ .../vault/data/RequestInterceptor.java | 6 + v2/src/main/java/com/skyflow/Skyflow.java | 234 +++++------------- .../com/skyflow/vault/data/InsertRequest.java | 6 +- .../controller/ConnectionControllerTests.java | 1 + .../com/skyflow/vault/data/DeleteTests.java | 1 + .../java/com/skyflow/vault/data/GetTests.java | 5 +- .../com/skyflow/vault/data/InsertTests.java | 5 +- .../com/skyflow/vault/data/QueryTests.java | 5 +- .../com/skyflow/vault/data/UpdateTests.java | 5 +- .../skyflow/vault/tokens/TokenizeTests.java | 7 +- 18 files changed, 493 insertions(+), 319 deletions(-) create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/InsertOptions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/InsertRecord.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/RequestContext.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/RequestInterceptor.java diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java index 83e31c1e..2b752e14 100644 --- a/common/src/main/java/com/skyflow/BaseSkyflow.java +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -1,29 +1,115 @@ package com.skyflow; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; import com.skyflow.enums.LogLevel; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.utils.BaseUtils; import com.skyflow.utils.logger.LogUtil; +import com.skyflow.utils.validations.BaseValidations; -class BaseSkyflow { - private final BaseSkyflowClientBuilder builder; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; - protected BaseSkyflow(BaseSkyflowClientBuilder builder) { +abstract class BaseSkyflow implements ISkyflow { + protected final BaseSkyflowClientBuilder builder; + + protected BaseSkyflow(BaseSkyflowClientBuilder builder) { this.builder = builder; LogUtil.printInfoLog(InfoLogs.CLIENT_INITIALIZED.getLog()); } + protected abstract Self self(); + + @Override + public Self addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + this.builder.addVaultConfigTemplate(vaultConfig); + return self(); + } + + public VaultConfig getVaultConfig(String vaultId) { + return this.builder.vaultConfigMap.get(vaultId); + } + + @Override + public Self updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + this.builder.updateVaultConfigTemplate(vaultConfig); + return self(); + } + + @Override + public Self removeVaultConfig(String vaultId) throws SkyflowException { + this.builder.removeVaultConfigTemplate(vaultId); + return self(); + } + + @Override + public Self updateSkyflowCredentials(Credentials credentials) throws SkyflowException { + this.builder.addSkyflowCredentialsTemplate(credentials); + return self(); + } + + @Override + public Self setLogLevel(LogLevel logLevel) { + this.builder.setLogLevel(logLevel); + return self(); + } + + @Override public LogLevel getLogLevel() { return this.builder.logLevel; } - static class BaseSkyflowClientBuilder { + @Override + public VC vault() throws SkyflowException { + return resolveOrThrow(this.builder.vaultClientsMap, null, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); + } + + protected static T resolveOrThrow(Map map, String key, + ErrorLogs errorLog, ErrorMessage errorMessage) throws SkyflowException { + T value = key != null ? map.get(key) : map.values().stream().findFirst().orElse(null); + if (value == null) { + LogUtil.printErrorLog(errorLog.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), errorMessage.getMessage()); + } + return value; + } + + abstract static class BaseSkyflowClientBuilder { + protected final LinkedHashMap vaultConfigMap = new LinkedHashMap<>(); + protected final LinkedHashMap vaultClientsMap = new LinkedHashMap<>(); + protected Credentials skyflowCredentials; protected LogLevel logLevel = LogLevel.ERROR; protected BaseSkyflowClientBuilder() { } - protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { + public BaseSkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + addVaultConfigTemplate(vaultConfig); + return this; + } + + public BaseSkyflowClientBuilder updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + updateVaultConfigTemplate(vaultConfig); + return this; + } + + public BaseSkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { + removeVaultConfigTemplate(vaultId); + return this; + } + + public BaseSkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { + addSkyflowCredentialsTemplate(credentials); + return this; + } + + protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel; LogUtil.setupLogger(this.logLevel); LogUtil.printInfoLog(BaseUtils.parameterizedString( @@ -31,6 +117,81 @@ protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { )); return this; } + + protected final void addVaultConfigTemplate(VaultConfig vaultConfig) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); + validateVaultConfig(vaultConfig); + VaultConfig vaultConfigCopy; + try { + vaultConfigCopy = (VaultConfig) vaultConfig.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + if (this.vaultClientsMap.containsKey(vaultConfigCopy.getVaultId())) { + LogUtil.printErrorLog(BaseUtils.parameterizedString( + ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfigCopy.getVaultId() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), + ErrorMessage.VaultIdAlreadyInConfigList.getMessage()); + } + this.vaultConfigMap.put(vaultConfigCopy.getVaultId(), vaultConfigCopy); + onVaultConfigAdded(vaultConfigCopy); + } + + protected final void updateVaultConfigTemplate(VaultConfig vaultConfig) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); + validateVaultConfig(vaultConfig); + if (!this.vaultClientsMap.containsKey(vaultConfig.getVaultId())) { + LogUtil.printErrorLog(BaseUtils.parameterizedString( + ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultConfig.getVaultId() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + } + VaultConfig previousConfig = this.vaultConfigMap.get(vaultConfig.getVaultId()); + if (vaultConfig.getEnv() != null) { + previousConfig.setEnv(vaultConfig.getEnv()); + } + if (vaultConfig.getClusterId() != null) { + previousConfig.setClusterId(vaultConfig.getClusterId()); + } + if (vaultConfig.getCredentials() != null) { + try { + previousConfig.setCredentials((Credentials) vaultConfig.getCredentials().clone()); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + onVaultConfigUpdated(previousConfig); + } + + protected final void removeVaultConfigTemplate(String vaultId) throws SkyflowException { + if (!this.vaultClientsMap.containsKey(vaultId)) { + LogUtil.printErrorLog(BaseUtils.parameterizedString(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId)); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + } + this.vaultClientsMap.remove(vaultId); + this.vaultConfigMap.remove(vaultId); + } + + protected final void addSkyflowCredentialsTemplate(Credentials credentials) throws SkyflowException { + BaseValidations.validateCredentials(credentials); + Credentials credentialsCopy; + try { + credentialsCopy = (Credentials) credentials.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + this.skyflowCredentials = credentialsCopy; + onCredentialsUpdated(credentialsCopy); + } + + protected abstract void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException; + + protected abstract void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException; + + protected abstract void onVaultConfigUpdated(VaultConfig updatedConfig) throws SkyflowException; + + protected abstract void onCredentialsUpdated(Credentials credentials) throws SkyflowException; } } diff --git a/common/src/main/java/com/skyflow/ISkyflow.java b/common/src/main/java/com/skyflow/ISkyflow.java index f756ed2f..55879a6c 100644 --- a/common/src/main/java/com/skyflow/ISkyflow.java +++ b/common/src/main/java/com/skyflow/ISkyflow.java @@ -1,11 +1,9 @@ package com.skyflow; -import com.skyflow.config.BaseCredentials; -import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.LogLevel; import com.skyflow.errors.SkyflowException; -public interface ISkyflow, V extends BaseVaultConfig, C extends BaseCredentials, VC> { +public interface ISkyflow { Self addVaultConfig(V vaultConfig) throws SkyflowException; Self updateVaultConfig(V vaultConfig) throws SkyflowException; diff --git a/common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java index 9f463b6f..d2f6f812 100644 --- a/common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java +++ b/common/src/main/java/com/skyflow/vault/data/BaseInsertRequest.java @@ -1,4 +1,25 @@ package com.skyflow.vault.data; -public class BaseInsertRequest { +class BaseInsertRequest { + private final BaseInsertRequestBuilder builder; + + protected BaseInsertRequest(BaseInsertRequestBuilder builder) { + this.builder = builder; + } + + public String getTable() { + return this.builder.table; + } + + static class BaseInsertRequestBuilder { + protected String table; + protected BaseInsertRequestBuilder() { + } + + public BaseInsertRequestBuilder table(String table) { + this.table = table; + return this; + } + + } } diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java index cb5676e4..f534c1da 100644 --- a/flowvault/src/main/java/com/skyflow/Skyflow.java +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -3,10 +3,7 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.LogLevel; -import com.skyflow.errors.ErrorCode; -import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; -import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.utils.Constants; import com.skyflow.utils.SdkVersion; @@ -15,15 +12,15 @@ import com.skyflow.utils.validations.Validations; import com.skyflow.vault.controller.VaultController; -import java.util.LinkedHashMap; - -public final class Skyflow extends BaseSkyflow - implements ISkyflow { - private final SkyflowClientBuilder builder; +public final class Skyflow extends BaseSkyflow { private Skyflow(SkyflowClientBuilder builder) { super(builder); - this.builder = builder; + } + + @Override + protected Skyflow self() { + return this; } public static SkyflowClientBuilder builder() { @@ -36,136 +33,52 @@ public VaultConfig getVaultConfig() { return (VaultConfig) array[0]; } - public VaultConfig getVaultConfig(String vaultId) { - return this.builder.vaultConfigMap.get(vaultId); - } + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { - @Override - public Skyflow addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - this.builder.addVaultConfig(vaultConfig); - return this; - } - - @Override - public Skyflow updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - this.builder.updateVaultConfig(vaultConfig); - return this; - } - - @Override - public Skyflow removeVaultConfig(String vaultId) throws SkyflowException { - this.builder.removeVaultConfig(vaultId); - return this; - } - - @Override - public Skyflow updateSkyflowCredentials(Credentials credentials) throws SkyflowException { - this.builder.addSkyflowCredentials(credentials); - return this; - } - - @Override - public Skyflow setLogLevel(LogLevel logLevel) { - this.builder.setLogLevel(logLevel); - return this; - } + @Override + protected void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + Validations.validateVaultConfiguration(vaultConfig); + } - @Override - public VaultController vault() throws SkyflowException { - Object[] array = this.builder.vaultClientsMap.keySet().toArray(); - if (array.length < 1) { - LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + @Override + protected void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException { + this.vaultClientsMap.put(vaultConfig.getVaultId(), new VaultController(vaultConfig, this.skyflowCredentials)); + LogUtil.printInfoLog(Utils.parameterizedString(InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfig.getVaultId())); } - String vaultId = (String) array[0]; - return this.vault(vaultId); - } - public VaultController vault(String vaultId) throws SkyflowException { - VaultController controller = this.builder.vaultClientsMap.get(vaultId); - if (controller == null) { - LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + @Override + protected void onVaultConfigUpdated(VaultConfig updatedConfig) throws SkyflowException { + this.vaultClientsMap.put(updatedConfig.getVaultId(), new VaultController(updatedConfig, this.skyflowCredentials)); } - return controller; - } - public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { - private final LinkedHashMap vaultConfigMap; - private final LinkedHashMap vaultClientsMap; - protected Credentials skyflowCredentials; - public SkyflowClientBuilder() { - this.vaultConfigMap = new LinkedHashMap<>(); - this.vaultClientsMap = new LinkedHashMap<>(); + @Override + protected void onCredentialsUpdated(Credentials credentials) throws SkyflowException { + for (VaultController vault : this.vaultClientsMap.values()) { + vault.setCommonCredentials(credentials); + } } + @Override public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); - Validations.validateVaultConfiguration(vaultConfig); - VaultConfig vaultConfigCopy; - try { - vaultConfigCopy = (VaultConfig) vaultConfig.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - if (this.vaultClientsMap.containsKey(vaultConfigCopy.getVaultId())) { - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfigCopy.getVaultId() - )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), - ErrorMessage.VaultIdAlreadyInConfigList.getMessage()); - } else { - this.vaultConfigMap.put(vaultConfigCopy.getVaultId(), vaultConfigCopy); // add new config in map - this.vaultClientsMap.put(vaultConfigCopy.getVaultId(), new VaultController(vaultConfigCopy, this.skyflowCredentials)); // add new controller with new config - LogUtil.printInfoLog(Utils.parameterizedString( - InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfigCopy.getVaultId())); - } + super.addVaultConfig(vaultConfig); return this; } + @Override public SkyflowClientBuilder updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); - Validations.validateVaultConfiguration(vaultConfig); - if (this.vaultClientsMap.containsKey(vaultConfig.getVaultId())) { - VaultConfig existing = this.vaultConfigMap.get(vaultConfig.getVaultId()); - if (vaultConfig.getEnv() != null) existing.setEnv(vaultConfig.getEnv()); - if (vaultConfig.getClusterId() != null) existing.setClusterId(vaultConfig.getClusterId()); - if (vaultConfig.getCredentials() != null) existing.setCredentials(vaultConfig.getCredentials()); - this.vaultClientsMap.put(existing.getVaultId(), new VaultController(existing, this.skyflowCredentials)); - } else { - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultConfig.getVaultId() - )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); - } + super.updateVaultConfig(vaultConfig); return this; } + @Override public SkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { - if (this.vaultClientsMap.containsKey(vaultId)) { - this.vaultClientsMap.remove(vaultId); - this.vaultConfigMap.remove(vaultId); - } else { - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId - )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); - } + super.removeVaultConfig(vaultId); return this; } + @Override public SkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { - Validations.validateCredentials(credentials); - Credentials credentialsCopy; - try { - credentialsCopy = (Credentials) credentials.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - this.skyflowCredentials = credentialsCopy; - for (VaultController vault : this.vaultClientsMap.values()) { - vault.setCommonCredentials(this.skyflowCredentials); - } + super.addSkyflowCredentials(credentials); return this; } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/InsertOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/InsertOptions.java new file mode 100644 index 00000000..73262b98 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/InsertOptions.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.data; + +public final class InsertOptions { + private final RequestInterceptor interceptor; + + private InsertOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public InsertOptions build() { + return new InsertOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/InsertRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/InsertRecord.java new file mode 100644 index 00000000..e9cb5c08 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/InsertRecord.java @@ -0,0 +1,68 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.UpsertType; + +import java.util.List; +import java.util.Map; + +public class InsertRecord { + private final InsertRecordBuilder builder; + + private InsertRecord(InsertRecordBuilder builder) { + this.builder = builder; + } + + // Getters + public String getTable() { + return this.builder.table; + } + + public Map getData() { + return this.builder.data; + } + + public List getUpsert() { + return this.builder.upsert; + } + + public UpsertType getUpsertType() { + return this.builder.upsertType; + } + + // Builder Class + public static final class InsertRecordBuilder{ + private String table; + private Map data; + private List upsert; + private UpsertType upsertType; + + public InsertRecordBuilder table(String table) { + this.table = table; + return this; + } + + public InsertRecordBuilder data(Map data) { + this.data = data; + return this; + } + + public InsertRecordBuilder upsert(List upsert) { + this.upsert = upsert; + return this; + } + + public InsertRecordBuilder upsertType(UpsertType upsertType) { + this.upsertType = upsertType; + return this; + } + + public InsertRecord build() { + return new InsertRecord(this); + } + } + + // Static entry point for builder + public static InsertRecordBuilder builder() { + return new InsertRecordBuilder(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java index b3c82df0..4d8e8cae 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java +++ b/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java @@ -1,4 +1,68 @@ package com.skyflow.vault.data; +import com.skyflow.enums.UpsertType; -public class InsertRequest extends BaseInsertRequest{ +import java.util.ArrayList; +import java.util.List; + +public class InsertRequest extends BaseInsertRequest { + private final InsertRequestBuilder builder; + + private InsertRequest(InsertRequestBuilder builder) { + super(builder); + this.builder = builder; + } + + + public static InsertRequestBuilder builder() { + return new InsertRequestBuilder(); + } + + public List getUpsert() { + return this.builder.upsert; + } + + public UpsertType getUpsertType() { + return this.builder.upsertType; + } + + public ArrayList getRecords(){ + return this.builder.records; + } + + public static final class InsertRequestBuilder extends BaseInsertRequestBuilder { + private List upsert; + + private UpsertType upsertType; + + private ArrayList records; + + private InsertRequestBuilder() { + super(); + } + + @Override + public InsertRequestBuilder table(String table) { + super.table(table); + return this; + } + + public InsertRequestBuilder upsert(List upsert) { + this.upsert = upsert; + return this; + } + + public InsertRequestBuilder upsertType(UpsertType upsertType) { + this.upsertType = upsertType; + return this; + } + + public InsertRequestBuilder records(ArrayList records){ + this.records = records; + return this; + } + + public InsertRequest build() { + return new InsertRequest(this); + } + } } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/RequestContext.java b/flowvault/src/main/java/com/skyflow/vault/data/RequestContext.java new file mode 100644 index 00000000..1473df50 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/RequestContext.java @@ -0,0 +1,26 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.CustomHeaderKey; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public final class RequestContext { + private final String operation; + private final Map headers = new HashMap<>(); + + public RequestContext(String operation, int batchIndex, int totalBatches) { + this.operation = operation; + } + + public String getOperation() { return operation; } + + public void addHeader(CustomHeaderKey key, String value) { + headers.put(key, value); + } + + public Map getHeaders() { + return Collections.unmodifiableMap(headers); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/RequestInterceptor.java b/flowvault/src/main/java/com/skyflow/vault/data/RequestInterceptor.java new file mode 100644 index 00000000..37f5261d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/RequestInterceptor.java @@ -0,0 +1,6 @@ +package com.skyflow.vault.data; + +@FunctionalInterface +public interface RequestInterceptor { + void intercept(RequestContext context); +} diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index d36c24e3..5e763fb9 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -3,15 +3,12 @@ import com.skyflow.config.ConnectionConfig; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; -import com.skyflow.enums.Env; import com.skyflow.enums.LogLevel; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; -import com.skyflow.utils.Constants; -import com.skyflow.utils.SdkVersion; import com.skyflow.utils.Utils; import com.skyflow.utils.logger.LogUtil; import com.skyflow.utils.validations.Validations; @@ -21,8 +18,7 @@ import java.util.LinkedHashMap; -public final class Skyflow extends BaseSkyflow - implements ISkyflow { +public final class Skyflow extends BaseSkyflow { private final SkyflowClientBuilder builder; private Skyflow(SkyflowClientBuilder builder) { @@ -30,43 +26,13 @@ private Skyflow(SkyflowClientBuilder builder) { this.builder = builder; } - public static SkyflowClientBuilder builder() { - SdkVersion.setSdkPrefix(Constants.SDK_PREFIX); - return new SkyflowClientBuilder(); - } - - @Override - public Skyflow addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - this.builder.addVaultConfig(vaultConfig); - return this; - } - - public VaultConfig getVaultConfig(String vaultId) { - return this.builder.vaultConfigMap.get(vaultId); - } - - @Override - public Skyflow updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - this.builder.updateVaultConfig(vaultConfig); - return this; - } - - @Override - public Skyflow removeVaultConfig(String vaultId) throws SkyflowException { - this.builder.removeVaultConfig(vaultId); - return this; - } - @Override - public Skyflow updateSkyflowCredentials(Credentials credentials) throws SkyflowException { - this.builder.addSkyflowCredentials(credentials); + protected Skyflow self() { return this; } - @Override - public Skyflow setLogLevel(LogLevel logLevel) { - this.builder.setLogLevel(logLevel); - return this; + public static SkyflowClientBuilder builder() { + return new SkyflowClientBuilder(); } public Skyflow addConnectionConfig(ConnectionConfig connectionConfig) throws SkyflowException { @@ -88,7 +54,6 @@ public Skyflow removeConnectionConfig(String connectionId) throws SkyflowExcepti return this; } - /** @deprecated Use {@link #setLogLevel(LogLevel)} instead. */ @Deprecated(since = "2.1", forRemoval = true) public Skyflow updateLogLevel(LogLevel logLevel) { @@ -96,132 +61,60 @@ public Skyflow updateLogLevel(LogLevel logLevel) { return setLogLevel(logLevel); } - @Override - public VaultController vault() throws SkyflowException { - Object[] array = this.builder.vaultClientsMap.keySet().toArray(); - if (array.length < 1) { - LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); - } - String vaultId = (String) array[0]; - return this.vault(vaultId); - } - public VaultController vault(String vaultId) throws SkyflowException { - VaultController controller = this.builder.vaultClientsMap.get(vaultId); - if (controller == null) { - LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); - } - return controller; + return resolveOrThrow(this.builder.vaultClientsMap, vaultId, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } - public ConnectionController connection() throws SkyflowException { - Object[] array = this.builder.connectionsMap.keySet().toArray(); - if (array.length < 1) { - LogUtil.printErrorLog(ErrorLogs.CONNECTION_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.ConnectionIdNotInConfigList.getMessage()); - } - String connectionId = (String) array[0]; - return this.connection(connectionId); + return resolveOrThrow(this.builder.connectionsMap, null, ErrorLogs.CONNECTION_CONFIG_DOES_NOT_EXIST, ErrorMessage.ConnectionIdNotInConfigList); } public ConnectionController connection(String connectionId) throws SkyflowException { - ConnectionController controller = this.builder.connectionsMap.get(connectionId); - if (controller == null) { - LogUtil.printErrorLog(ErrorLogs.CONNECTION_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.ConnectionIdNotInConfigList.getMessage()); - } - return controller; + return resolveOrThrow(this.builder.connectionsMap, connectionId, ErrorLogs.CONNECTION_CONFIG_DOES_NOT_EXIST, ErrorMessage.ConnectionIdNotInConfigList); } public DetectController detect() throws SkyflowException { - Object[] array = this.builder.detectClientsMap.keySet().toArray(); - if (array.length < 1) { - LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); - } - String detectId = (String) array[0]; - return this.detect(detectId); + return resolveOrThrow(this.builder.detectClientsMap, null, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } public DetectController detect(String vaultId) throws SkyflowException { - DetectController controller = this.builder.detectClientsMap.get(vaultId); - if (controller == null) { - LogUtil.printErrorLog(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog()); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); - } - return controller; + return resolveOrThrow(this.builder.detectClientsMap, vaultId, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } - public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { - private final LinkedHashMap connectionsMap; - private final LinkedHashMap vaultClientsMap; - private final LinkedHashMap detectClientsMap; - private final LinkedHashMap vaultConfigMap; - private final LinkedHashMap connectionConfigMap; - private Credentials skyflowCredentials; - public SkyflowClientBuilder() { - this.vaultClientsMap = new LinkedHashMap<>(); - this.detectClientsMap = new LinkedHashMap<>(); - this.vaultConfigMap = new LinkedHashMap<>(); - this.connectionsMap = new LinkedHashMap<>(); - this.connectionConfigMap = new LinkedHashMap<>(); - this.skyflowCredentials = null; - } + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + private final LinkedHashMap connectionsMap = new LinkedHashMap<>(); + private final LinkedHashMap detectClientsMap = new LinkedHashMap<>(); + private final LinkedHashMap connectionConfigMap = new LinkedHashMap<>(); - public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); + @Override + protected void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { Validations.validateVaultConfig(vaultConfig); - VaultConfig vaultConfigCopy; - try { - vaultConfigCopy = (VaultConfig) vaultConfig.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - if (this.vaultClientsMap.containsKey(vaultConfigCopy.getVaultId())) { - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfigCopy.getVaultId() - )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), - ErrorMessage.VaultIdAlreadyInConfigList.getMessage()); - } else { - this.vaultConfigMap.put(vaultConfigCopy.getVaultId(), vaultConfigCopy); - this.vaultClientsMap.put(vaultConfigCopy.getVaultId(), new VaultController(vaultConfigCopy, this.skyflowCredentials)); - this.detectClientsMap.put(vaultConfigCopy.getVaultId(), new DetectController(vaultConfigCopy, this.skyflowCredentials)); - LogUtil.printInfoLog(Utils.parameterizedString( - InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfigCopy.getVaultId())); - LogUtil.printInfoLog(Utils.parameterizedString( - InfoLogs.DETECT_CONTROLLER_INITIALIZED.getLog(), vaultConfigCopy.getVaultId())); - } - return this; } - public SkyflowClientBuilder updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { - LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); - Validations.validateVaultConfig(vaultConfig); - if (this.vaultClientsMap.containsKey(vaultConfig.getVaultId())) { - VaultConfig updatedConfig = findAndUpdateVaultConfig(vaultConfig); - this.vaultClientsMap.get(updatedConfig.getVaultId()).updateVaultConfig(); - } else { - LogUtil.printErrorLog(Utils.parameterizedString( - ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultConfig.getVaultId() - )); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); - } - return this; + @Override + protected void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException { + this.vaultClientsMap.put(vaultConfig.getVaultId(), new VaultController(vaultConfig, this.skyflowCredentials)); + this.detectClientsMap.put(vaultConfig.getVaultId(), new DetectController(vaultConfig, this.skyflowCredentials)); + LogUtil.printInfoLog(Utils.parameterizedString(InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfig.getVaultId())); + LogUtil.printInfoLog(Utils.parameterizedString(InfoLogs.DETECT_CONTROLLER_INITIALIZED.getLog(), vaultConfig.getVaultId())); } - public SkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { - if (this.vaultClientsMap.containsKey(vaultId)) { - this.vaultClientsMap.remove(vaultId); - this.vaultConfigMap.remove(vaultId); - } else { - LogUtil.printErrorLog(Utils.parameterizedString(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId)); - throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); + @Override + protected void onVaultConfigUpdated(VaultConfig updatedConfig) throws SkyflowException { + this.vaultClientsMap.get(updatedConfig.getVaultId()).updateVaultConfig(); + } + + @Override + protected void onCredentialsUpdated(Credentials credentials) throws SkyflowException { + for (VaultController vault : this.vaultClientsMap.values()) { + vault.setCommonCredentials(credentials); + } + for (DetectController detect : this.detectClientsMap.values()) { + detect.setCommonCredentials(credentials); + } + for (ConnectionController connection : this.connectionsMap.values()) { + connection.setCommonCredentials(credentials); } - return this; } public SkyflowClientBuilder addConnectionConfig(ConnectionConfig connectionConfig) throws SkyflowException { @@ -273,24 +166,27 @@ public SkyflowClientBuilder removeConnectionConfig(String connectionId) throws S return this; } + @Override + public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + super.addVaultConfig(vaultConfig); + return this; + } + + @Override + public SkyflowClientBuilder updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + super.updateVaultConfig(vaultConfig); + return this; + } + + @Override + public SkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { + super.removeVaultConfig(vaultId); + return this; + } + + @Override public SkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { - Validations.validateCredentials(credentials); - Credentials credentialsCopy; - try { - credentialsCopy = (Credentials) credentials.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - this.skyflowCredentials = credentialsCopy; - for (VaultController vault : this.vaultClientsMap.values()) { - vault.setCommonCredentials(this.skyflowCredentials); - } - for (DetectController detect : this.detectClientsMap.values()) { - detect.setCommonCredentials(this.skyflowCredentials); - } - for (ConnectionController connection : this.connectionsMap.values()) { - connection.setCommonCredentials(this.skyflowCredentials); - } + super.addSkyflowCredentials(credentials); return this; } @@ -304,24 +200,6 @@ public Skyflow build() { return new Skyflow(this); } - private VaultConfig findAndUpdateVaultConfig(VaultConfig vaultConfig) { - VaultConfig previousConfig = this.vaultConfigMap.get(vaultConfig.getVaultId()); - Env env = vaultConfig.getEnv() != null ? vaultConfig.getEnv() : previousConfig.getEnv(); - String clusterId = vaultConfig.getClusterId() != null ? vaultConfig.getClusterId() : previousConfig.getClusterId(); - Credentials credentials = previousConfig.getCredentials(); - if (vaultConfig.getCredentials() != null) { - try { - credentials = (Credentials) vaultConfig.getCredentials().clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - previousConfig.setEnv(env); - previousConfig.setClusterId(clusterId); - previousConfig.setCredentials(credentials); - return previousConfig; - } - private ConnectionConfig findAndUpdateConnectionConfig(ConnectionConfig connectionConfig) { ConnectionConfig previousConfig = this.connectionConfigMap.get(connectionConfig.getConnectionId()); String connectionURL = connectionConfig.getConnectionUrl() != null ? connectionConfig.getConnectionUrl() : previousConfig.getConnectionUrl(); diff --git a/v2/src/main/java/com/skyflow/vault/data/InsertRequest.java b/v2/src/main/java/com/skyflow/vault/data/InsertRequest.java index 54093467..f2127a77 100644 --- a/v2/src/main/java/com/skyflow/vault/data/InsertRequest.java +++ b/v2/src/main/java/com/skyflow/vault/data/InsertRequest.java @@ -5,13 +5,15 @@ import java.util.ArrayList; import java.util.HashMap; -public class InsertRequest { +public class InsertRequest extends BaseInsertRequest{ private final InsertRequestBuilder builder; private InsertRequest(InsertRequestBuilder builder) { + super(builder); this.builder = builder; } + public static InsertRequestBuilder builder() { return new InsertRequestBuilder(); } @@ -48,7 +50,7 @@ public TokenMode getTokenMode() { return this.builder.tokenMode; } - public static final class InsertRequestBuilder { + public static final class InsertRequestBuilder extends BaseInsertRequestBuilder{ private String table; private ArrayList> values; private ArrayList> tokens; diff --git a/v2/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java b/v2/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java index ddbe519e..a258e01d 100644 --- a/v2/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java +++ b/v2/src/test/java/com/skyflow/vault/controller/ConnectionControllerTests.java @@ -2,6 +2,7 @@ import com.skyflow.Skyflow; import com.skyflow.config.ConnectionConfig; +import com.skyflow.config.Credentials; import com.skyflow.enums.LogLevel; import com.skyflow.enums.RequestMethod; import com.skyflow.errors.ErrorCode; diff --git a/v2/src/test/java/com/skyflow/vault/data/DeleteTests.java b/v2/src/test/java/com/skyflow/vault/data/DeleteTests.java index 1cef1c17..ae294f24 100644 --- a/v2/src/test/java/com/skyflow/vault/data/DeleteTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/DeleteTests.java @@ -2,6 +2,7 @@ import com.skyflow.Skyflow; import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.Credentials; import com.skyflow.enums.Env; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; diff --git a/v2/src/test/java/com/skyflow/vault/data/GetTests.java b/v2/src/test/java/com/skyflow/vault/data/GetTests.java index ec0f112e..bc6f24ef 100644 --- a/v2/src/test/java/com/skyflow/vault/data/GetTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/GetTests.java @@ -1,7 +1,8 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.VaultConfig; +import com.skyflow.config.Credentials; import com.skyflow.enums.Env; import com.skyflow.enums.RedactionType; import com.skyflow.errors.ErrorCode; @@ -42,7 +43,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/v2/src/test/java/com/skyflow/vault/data/InsertTests.java b/v2/src/test/java/com/skyflow/vault/data/InsertTests.java index 43211f4c..0ba6c7f8 100644 --- a/v2/src/test/java/com/skyflow/vault/data/InsertTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/InsertTests.java @@ -1,7 +1,8 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.VaultConfig; +import com.skyflow.config.Credentials; import com.skyflow.enums.Env; import com.skyflow.enums.TokenMode; import com.skyflow.errors.ErrorCode; @@ -41,7 +42,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/v2/src/test/java/com/skyflow/vault/data/QueryTests.java b/v2/src/test/java/com/skyflow/vault/data/QueryTests.java index 862006f4..c8e453f5 100644 --- a/v2/src/test/java/com/skyflow/vault/data/QueryTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/QueryTests.java @@ -1,7 +1,8 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; @@ -33,7 +34,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/v2/src/test/java/com/skyflow/vault/data/UpdateTests.java b/v2/src/test/java/com/skyflow/vault/data/UpdateTests.java index 0523d6cc..ca334976 100644 --- a/v2/src/test/java/com/skyflow/vault/data/UpdateTests.java +++ b/v2/src/test/java/com/skyflow/vault/data/UpdateTests.java @@ -1,7 +1,8 @@ package com.skyflow.vault.data; import com.skyflow.Skyflow; -import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.VaultConfig; +import com.skyflow.config.Credentials; import com.skyflow.enums.Env; import com.skyflow.enums.TokenMode; import com.skyflow.errors.ErrorCode; @@ -36,7 +37,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); diff --git a/v2/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java b/v2/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java index debfe10a..27563a57 100644 --- a/v2/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java +++ b/v2/src/test/java/com/skyflow/vault/tokens/TokenizeTests.java @@ -1,7 +1,8 @@ package com.skyflow.vault.tokens; import com.skyflow.Skyflow; -import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.VaultConfig; +import com.skyflow.config.Credentials; import com.skyflow.enums.Env; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; @@ -20,7 +21,7 @@ public class TokenizeTests { private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; private static String vaultID = null; private static String clusterID = null; - private static BaseVaultConfig vaultConfig = null; + private static VaultConfig vaultConfig = null; private static String token = null; private static ArrayList tokens = null; private static Skyflow skyflowClient = null; @@ -37,7 +38,7 @@ public static void setup() { Credentials credentials = new Credentials(); credentials.setToken("valid-token"); - vaultConfig = new BaseVaultConfig(); + vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.DEV); From 77ec4af17d6d2dd9ccef2dafa442906b2dc3e9d5 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Tue, 14 Jul 2026 19:05:37 +0530 Subject: [PATCH 06/28] SK-2967 move vault url in v3 --- .../main/java/com/skyflow/BaseSkyflow.java | 89 ++++++++----------- .../java/com/skyflow/BaseVaultClient.java | 9 +- .../com/skyflow/config/BaseVaultConfig.java | 22 +++-- .../java/com/skyflow/config/VaultConfig.java | 30 ------- .../src/main/java/com/skyflow/Skyflow.java | 36 +++++++- .../main/java/com/skyflow/VaultClient.java | 2 +- .../java/com/skyflow/config/VaultConfig.java | 20 +++++ v2/src/main/java/com/skyflow/Skyflow.java | 36 +++++++- v2/src/main/java/com/skyflow/VaultClient.java | 2 +- .../java/com/skyflow/config/VaultConfig.java | 9 ++ 10 files changed, 154 insertions(+), 101 deletions(-) delete mode 100644 common/src/main/java/com/skyflow/config/VaultConfig.java create mode 100644 flowvault/src/main/java/com/skyflow/config/VaultConfig.java create mode 100644 v2/src/main/java/com/skyflow/config/VaultConfig.java diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java index 2b752e14..97f19a80 100644 --- a/common/src/main/java/com/skyflow/BaseSkyflow.java +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -1,7 +1,6 @@ package com.skyflow; import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; import com.skyflow.enums.LogLevel; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; @@ -13,59 +12,52 @@ import com.skyflow.utils.validations.BaseValidations; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -abstract class BaseSkyflow implements ISkyflow { - protected final BaseSkyflowClientBuilder builder; - protected BaseSkyflow(BaseSkyflowClientBuilder builder) { +abstract class BaseSkyflow implements ISkyflow { + protected final BaseSkyflowClientBuilder builder; + + protected BaseSkyflow(BaseSkyflowClientBuilder builder) { this.builder = builder; LogUtil.printInfoLog(InfoLogs.CLIENT_INITIALIZED.getLog()); } protected abstract Self self(); - @Override - public Self addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + public Self addVaultConfig(V vaultConfig) throws SkyflowException { this.builder.addVaultConfigTemplate(vaultConfig); return self(); } - public VaultConfig getVaultConfig(String vaultId) { + public V getVaultConfig(String vaultId) { return this.builder.vaultConfigMap.get(vaultId); } - @Override - public Self updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + public Self updateVaultConfig(V vaultConfig) throws SkyflowException { this.builder.updateVaultConfigTemplate(vaultConfig); return self(); } - @Override public Self removeVaultConfig(String vaultId) throws SkyflowException { this.builder.removeVaultConfigTemplate(vaultId); return self(); } - @Override public Self updateSkyflowCredentials(Credentials credentials) throws SkyflowException { this.builder.addSkyflowCredentialsTemplate(credentials); return self(); } - @Override public Self setLogLevel(LogLevel logLevel) { this.builder.setLogLevel(logLevel); return self(); } - @Override public LogLevel getLogLevel() { return this.builder.logLevel; } - @Override public VC vault() throws SkyflowException { return resolveOrThrow(this.builder.vaultClientsMap, null, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } @@ -80,8 +72,8 @@ protected static T resolveOrThrow(Map map, String key, return value; } - abstract static class BaseSkyflowClientBuilder { - protected final LinkedHashMap vaultConfigMap = new LinkedHashMap<>(); + abstract static class BaseSkyflowClientBuilder { + protected final LinkedHashMap vaultConfigMap = new LinkedHashMap<>(); protected final LinkedHashMap vaultClientsMap = new LinkedHashMap<>(); protected Credentials skyflowCredentials; protected LogLevel logLevel = LogLevel.ERROR; @@ -89,27 +81,27 @@ abstract static class BaseSkyflowClientBuilder { protected BaseSkyflowClientBuilder() { } - public BaseSkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + public BaseSkyflowClientBuilder addVaultConfig(V vaultConfig) throws SkyflowException { addVaultConfigTemplate(vaultConfig); return this; } - public BaseSkyflowClientBuilder updateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { + public BaseSkyflowClientBuilder updateVaultConfig(V vaultConfig) throws SkyflowException { updateVaultConfigTemplate(vaultConfig); return this; } - public BaseSkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { + public BaseSkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { removeVaultConfigTemplate(vaultId); return this; } - public BaseSkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { + public BaseSkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { addSkyflowCredentialsTemplate(credentials); return this; } - protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { + protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel; LogUtil.setupLogger(this.logLevel); LogUtil.printInfoLog(BaseUtils.parameterizedString( @@ -118,50 +110,35 @@ protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { return this; } - protected final void addVaultConfigTemplate(VaultConfig vaultConfig) throws SkyflowException { + protected final void addVaultConfigTemplate(V vaultConfig) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); validateVaultConfig(vaultConfig); - VaultConfig vaultConfigCopy; - try { - vaultConfigCopy = (VaultConfig) vaultConfig.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - if (this.vaultClientsMap.containsKey(vaultConfigCopy.getVaultId())) { + V vaultConfigCopy = cloneVaultConfig(vaultConfig); + String vaultId = extractVaultId(vaultConfigCopy); + if (this.vaultClientsMap.containsKey(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString( - ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultConfigCopy.getVaultId() + ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultId )); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdAlreadyInConfigList.getMessage()); } - this.vaultConfigMap.put(vaultConfigCopy.getVaultId(), vaultConfigCopy); + this.vaultConfigMap.put(vaultId, vaultConfigCopy); onVaultConfigAdded(vaultConfigCopy); } - protected final void updateVaultConfigTemplate(VaultConfig vaultConfig) throws SkyflowException { + protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); validateVaultConfig(vaultConfig); - if (!this.vaultClientsMap.containsKey(vaultConfig.getVaultId())) { + String vaultId = extractVaultId(vaultConfig); + if (!this.vaultClientsMap.containsKey(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString( - ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultConfig.getVaultId() + ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId )); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); } - VaultConfig previousConfig = this.vaultConfigMap.get(vaultConfig.getVaultId()); - if (vaultConfig.getEnv() != null) { - previousConfig.setEnv(vaultConfig.getEnv()); - } - if (vaultConfig.getClusterId() != null) { - previousConfig.setClusterId(vaultConfig.getClusterId()); - } - if (vaultConfig.getCredentials() != null) { - try { - previousConfig.setCredentials((Credentials) vaultConfig.getCredentials().clone()); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - onVaultConfigUpdated(previousConfig); + V previousConfig = this.vaultConfigMap.get(vaultId); + V merged = mergeVaultConfig(vaultConfig, previousConfig); + onVaultConfigUpdated(merged); } protected final void removeVaultConfigTemplate(String vaultId) throws SkyflowException { @@ -185,11 +162,17 @@ protected final void addSkyflowCredentialsTemplate(Credentials credentials) thro onCredentialsUpdated(credentialsCopy); } - protected abstract void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException; + protected abstract void validateVaultConfig(V vaultConfig) throws SkyflowException; + + protected abstract V cloneVaultConfig(V vaultConfig); + + protected abstract String extractVaultId(V vaultConfig); + + protected abstract V mergeVaultConfig(V incoming, V existing); - protected abstract void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException; + protected abstract void onVaultConfigAdded(V vaultConfig) throws SkyflowException; - protected abstract void onVaultConfigUpdated(VaultConfig updatedConfig) throws SkyflowException; + protected abstract void onVaultConfigUpdated(V updatedConfig) throws SkyflowException; protected abstract void onCredentialsUpdated(Credentials credentials) throws SkyflowException; } diff --git a/common/src/main/java/com/skyflow/BaseVaultClient.java b/common/src/main/java/com/skyflow/BaseVaultClient.java index 2ce32997..7ca74cf4 100644 --- a/common/src/main/java/com/skyflow/BaseVaultClient.java +++ b/common/src/main/java/com/skyflow/BaseVaultClient.java @@ -3,7 +3,6 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.skyflow.config.BaseCredentials; -import com.skyflow.config.VaultConfig; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; @@ -25,8 +24,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -class BaseVaultClient { - protected VaultConfig vaultConfig; +class BaseVaultClient { + protected V vaultConfig; protected OkHttpClient sharedHttpClient; protected String currentVaultURL; protected BaseCredentials commonCredentials; @@ -34,12 +33,12 @@ class BaseVaultClient { protected String token; protected String apiKey; - protected BaseVaultClient(VaultConfig vaultConfig, BaseCredentials credentials) { + protected BaseVaultClient(V vaultConfig, BaseCredentials credentials) { this.vaultConfig = vaultConfig; this.commonCredentials = credentials; } - protected VaultConfig getVaultConfig() { + protected V getVaultConfig() { return vaultConfig; } diff --git a/common/src/main/java/com/skyflow/config/BaseVaultConfig.java b/common/src/main/java/com/skyflow/config/BaseVaultConfig.java index e59aeb91..fb1a2a6b 100644 --- a/common/src/main/java/com/skyflow/config/BaseVaultConfig.java +++ b/common/src/main/java/com/skyflow/config/BaseVaultConfig.java @@ -2,17 +2,17 @@ import com.skyflow.enums.Env; -public class BaseVaultConfig { +public class BaseVaultConfig implements Cloneable { private String vaultId; private String clusterId; - private String vaultURL; private Env env; + private Credentials credentials; public BaseVaultConfig() { this.vaultId = null; this.clusterId = null; - this.vaultURL = null; this.env = Env.PROD; + this.credentials = null; } public String getVaultId() { @@ -39,13 +39,21 @@ public void setEnv(Env env) { this.env = env == null ? Env.PROD : env; } + public Credentials getCredentials() { + return credentials; + } - public String getVaultURL() { - return vaultURL; + public void setCredentials(Credentials credentials) { + this.credentials = credentials; } - public void setVaultURL(String vaultURL) { - this.vaultURL = vaultURL; + @Override + public Object clone() throws CloneNotSupportedException { + BaseVaultConfig cloned = (BaseVaultConfig) super.clone(); + if (this.credentials != null) { + cloned.credentials = (Credentials) this.credentials.clone(); + } + return cloned; } } diff --git a/common/src/main/java/com/skyflow/config/VaultConfig.java b/common/src/main/java/com/skyflow/config/VaultConfig.java deleted file mode 100644 index bcb376a2..00000000 --- a/common/src/main/java/com/skyflow/config/VaultConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.skyflow.config; - -public class VaultConfig extends BaseVaultConfig implements Cloneable { - - private Credentials credentials; - - public VaultConfig() { - super(); - this.credentials = null; - } - - public Credentials getCredentials() { - return credentials; - } - - public void setCredentials(Credentials credentials) { - this.credentials = credentials; - } - - @Override - public Object clone() throws CloneNotSupportedException { - VaultConfig cloned = (VaultConfig) super.clone(); - if (this.credentials != null) { - cloned.credentials = (Credentials) this.credentials.clone(); - } - - return cloned; - } - -} diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java index f534c1da..51ccccd9 100644 --- a/flowvault/src/main/java/com/skyflow/Skyflow.java +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -12,7 +12,7 @@ import com.skyflow.utils.validations.Validations; import com.skyflow.vault.controller.VaultController; -public final class Skyflow extends BaseSkyflow { +public final class Skyflow extends BaseSkyflow { private Skyflow(SkyflowClientBuilder builder) { super(builder); @@ -33,13 +33,45 @@ public VaultConfig getVaultConfig() { return (VaultConfig) array[0]; } - public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { @Override protected void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { Validations.validateVaultConfiguration(vaultConfig); } + @Override + protected VaultConfig cloneVaultConfig(VaultConfig vaultConfig) { + try { + return (VaultConfig) vaultConfig.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + @Override + protected String extractVaultId(VaultConfig vaultConfig) { + return vaultConfig.getVaultId(); + } + + @Override + protected VaultConfig mergeVaultConfig(VaultConfig incoming, VaultConfig existing) { + if (incoming.getEnv() != null) { + existing.setEnv(incoming.getEnv()); + } + if (incoming.getClusterId() != null) { + existing.setClusterId(incoming.getClusterId()); + } + if (incoming.getCredentials() != null) { + try { + existing.setCredentials((Credentials) incoming.getCredentials().clone()); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + return existing; + } + @Override protected void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException { this.vaultClientsMap.put(vaultConfig.getVaultId(), new VaultController(vaultConfig, this.skyflowCredentials)); diff --git a/flowvault/src/main/java/com/skyflow/VaultClient.java b/flowvault/src/main/java/com/skyflow/VaultClient.java index e7d395a7..c8843f3e 100644 --- a/flowvault/src/main/java/com/skyflow/VaultClient.java +++ b/flowvault/src/main/java/com/skyflow/VaultClient.java @@ -8,7 +8,7 @@ import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; import com.skyflow.utils.Utils; -public class VaultClient extends BaseVaultClient { +public class VaultClient extends BaseVaultClient { private final ApiClientBuilder apiClientBuilder; private ApiClient apiClient; diff --git a/flowvault/src/main/java/com/skyflow/config/VaultConfig.java b/flowvault/src/main/java/com/skyflow/config/VaultConfig.java new file mode 100644 index 00000000..8966d29f --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/config/VaultConfig.java @@ -0,0 +1,20 @@ +package com.skyflow.config; + +public class VaultConfig extends BaseVaultConfig { + + private String vaultURL; + + public VaultConfig() { + super(); + this.vaultURL = null; + } + + public String getVaultURL() { + return vaultURL; + } + + public void setVaultURL(String vaultURL) { + this.vaultURL = vaultURL; + } + +} diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index 5e763fb9..396291bd 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -18,7 +18,7 @@ import java.util.LinkedHashMap; -public final class Skyflow extends BaseSkyflow { +public final class Skyflow extends BaseSkyflow { private final SkyflowClientBuilder builder; private Skyflow(SkyflowClientBuilder builder) { @@ -81,7 +81,7 @@ public DetectController detect(String vaultId) throws SkyflowException { return resolveOrThrow(this.builder.detectClientsMap, vaultId, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } - public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { private final LinkedHashMap connectionsMap = new LinkedHashMap<>(); private final LinkedHashMap detectClientsMap = new LinkedHashMap<>(); private final LinkedHashMap connectionConfigMap = new LinkedHashMap<>(); @@ -91,6 +91,38 @@ protected void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowExcept Validations.validateVaultConfig(vaultConfig); } + @Override + protected VaultConfig cloneVaultConfig(VaultConfig vaultConfig) { + try { + return (VaultConfig) vaultConfig.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + @Override + protected String extractVaultId(VaultConfig vaultConfig) { + return vaultConfig.getVaultId(); + } + + @Override + protected VaultConfig mergeVaultConfig(VaultConfig incoming, VaultConfig existing) { + if (incoming.getEnv() != null) { + existing.setEnv(incoming.getEnv()); + } + if (incoming.getClusterId() != null) { + existing.setClusterId(incoming.getClusterId()); + } + if (incoming.getCredentials() != null) { + try { + existing.setCredentials((Credentials) incoming.getCredentials().clone()); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + return existing; + } + @Override protected void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException { this.vaultClientsMap.put(vaultConfig.getVaultId(), new VaultController(vaultConfig, this.skyflowCredentials)); diff --git a/v2/src/main/java/com/skyflow/VaultClient.java b/v2/src/main/java/com/skyflow/VaultClient.java index ef6381b5..a24ef8d2 100644 --- a/v2/src/main/java/com/skyflow/VaultClient.java +++ b/v2/src/main/java/com/skyflow/VaultClient.java @@ -44,7 +44,7 @@ import java.util.stream.Collectors; -public class VaultClient extends BaseVaultClient { +public class VaultClient extends BaseVaultClient { private final ApiClientBuilder apiClientBuilder; private ApiClient apiClient; diff --git a/v2/src/main/java/com/skyflow/config/VaultConfig.java b/v2/src/main/java/com/skyflow/config/VaultConfig.java new file mode 100644 index 00000000..2abd6a27 --- /dev/null +++ b/v2/src/main/java/com/skyflow/config/VaultConfig.java @@ -0,0 +1,9 @@ +package com.skyflow.config; + +public class VaultConfig extends BaseVaultConfig { + + public VaultConfig() { + super(); + } + +} From 0e9a9c79c728c84a9ab464d9bd166b0957d685b9 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Thu, 16 Jul 2026 16:04:53 +0530 Subject: [PATCH 07/28] SK-2967 update generated code --- .../workflows/flowvault-internal-release.yml | 27 ++ .github/workflows/shared-build-and-deploy.yml | 24 +- .../main/java/com/skyflow/BaseSkyflow.java | 35 +- .../vault/data/BaseDetokenizeData.java | 14 + .../data/BaseDetokenizeRecordResponse.java | 19 + .../vault/data/BaseDetokenizeResponse.java | 1 + .../vault/data/BaseInsertResponse.java | 27 ++ .../java/com/skyflow/BaseSkyflowTests.java | 340 ++++++++++++++++++ .../com/skyflow/BaseVaultClientTests.java | 165 +++++++++ .../skyflow/config/BaseVaultConfigTests.java | 75 ++++ .../com/skyflow/config/CredentialsTests.java | 46 ++- .../skyflow/errors/SkyflowExceptionTest.java | 0 .../serviceaccount/util/BearerTokenTests.java | 12 +- .../util/SignedDataTokensTests.java | 12 +- .../serviceaccount/util/TokenTests.java | 4 +- .../com/skyflow/utils/BaseUtilsTests.java | 138 +++++++ .../utils/logger/LogUtilLevelTests.java | 0 .../invalidPrivateKeyCredentials.json | 0 .../resources/invalidTokenURICredentials.json | 0 .../test/resources/noClientIDCredentials.json | 0 .../test/resources/noKeyIDCredentials.json | 0 .../resources/noPrivateKeyCredentials.json | 0 .../test/resources/noTokenURICredentials.json | 0 common/src/test/resources/notJson.txt | 1 + .../src/main/java/com/skyflow/Skyflow.java | 33 -- .../java/com/skyflow/enums/InterfaceName.java | 19 + .../main/java/com/skyflow/utils/Utils.java | 130 ++++++- .../utils/validations/Validations.java | 163 +++++++++ .../vault/controller/VaultController.java | 61 +++- .../skyflow/vault/data/DetokenizeData.java | 8 + .../vault/data/DetokenizeRecordResponse.java | 37 ++ .../skyflow/vault/data/DetokenizeRequest.java | 37 ++ .../vault/data/DetokenizeResponse.java | 29 +- .../com/skyflow/vault/data/InsertRequest.java | 1 - .../skyflow/vault/data/InsertResponse.java | 6 + .../vault/data/TokenGroupRedactions.java | 39 ++ .../skyflow/vault/data/TokenizeRequest.java | 4 + .../skyflow/vault/data/TokenizeResponse.java | 4 + pom.xml | 17 +- v2/src/main/java/com/skyflow/Skyflow.java | 32 -- .../com/skyflow/generated/rest/ApiClient.java | 10 - .../generated/rest/AsyncApiClient.java | 10 - .../generated/rest/core/ClientOptions.java | 2 +- .../generated/rest/core/FileStream.java | 6 +- .../rest/core/InputStreamRequestBody.java | 7 +- .../generated/rest/core/ObjectMappers.java | 2 - .../rest/core/QueryStringMapper.java | 7 +- .../rest/core/ResponseBodyInputStream.java | 3 +- .../rest/core/ResponseBodyReader.java | 3 +- .../generated/rest/core/RetryInterceptor.java | 5 +- .../rest/errors/BadRequestError.java | 9 +- .../rest/errors/UnauthorizedError.java | 9 +- .../resources/audit/AsyncRawAuditClient.java | 20 +- .../rest/resources/audit/RawAuditClient.java | 16 +- .../AuditServiceListAuditEventsRequest.java | 18 +- .../binlookup/AsyncRawBinLookupClient.java | 21 +- .../binlookup/RawBinLookupClient.java | 17 +- .../binlookup/requests/V1BinListRequest.java | 15 +- .../resources/files/AsyncFilesClient.java | 13 +- .../resources/files/AsyncRawFilesClient.java | 78 ++-- .../rest/resources/files/FilesClient.java | 12 +- .../rest/resources/files/RawFilesClient.java | 74 ++-- ...entifyFileAudioRequestDeidentifyAudio.java | 15 +- ...fyFileDocumentPdfRequestDeidentifyPdf.java | 15 +- ...entifyFileImageRequestDeidentifyImage.java | 15 +- .../files/requests/DeidentifyFileRequest.java | 15 +- ...identifyFileRequestDeidentifyDocument.java | 15 +- ...tifyFileRequestDeidentifyPresentation.java | 15 +- ...ntifyFileRequestDeidentifySpreadsheet.java | 15 +- ...fyFileRequestDeidentifyStructuredText.java | 15 +- .../DeidentifyFileRequestDeidentifyText.java | 15 +- .../files/requests/GetRunRequest.java | 9 +- .../ReidentifyFileRequestReidentifyFile.java | 11 +- .../guardrails/AsyncRawGuardrailsClient.java | 25 +- .../guardrails/RawGuardrailsClient.java | 21 +- .../requests/DetectGuardrailsRequest.java | 15 +- .../resources/query/AsyncRawQueryClient.java | 21 +- .../rest/resources/query/RawQueryClient.java | 17 +- .../QueryServiceExecuteQueryBody.java | 9 +- .../records/AsyncRawRecordsClient.java | 49 ++- .../resources/records/AsyncRecordsClient.java | 21 +- .../resources/records/RawRecordsClient.java | 45 ++- .../rest/resources/records/RecordsClient.java | 22 +- .../FileServiceUploadFileRequest.java | 9 +- .../RecordServiceBatchOperationBody.java | 15 +- .../RecordServiceBulkDeleteRecordBody.java | 15 +- .../RecordServiceBulkGetRecordRequest.java | 16 +- .../RecordServiceGetRecordRequest.java | 16 +- .../RecordServiceInsertRecordBody.java | 15 +- .../RecordServiceUpdateRecordBody.java | 9 +- .../records/requests/UploadFileV2Request.java | 11 +- .../strings/AsyncRawStringsClient.java | 29 +- .../resources/strings/RawStringsClient.java | 25 +- .../requests/DeidentifyStringRequest.java | 15 +- .../requests/ReidentifyStringRequest.java | 9 +- .../tokens/AsyncRawTokensClient.java | 21 +- .../resources/tokens/AsyncTokensClient.java | 1 - .../resources/tokens/RawTokensClient.java | 17 +- .../tokens/requests/V1DetokenizePayload.java | 15 +- .../tokens/requests/V1TokenizePayload.java | 15 +- .../rest/types/AuditEventContext.java | 9 +- .../generated/rest/types/AuditEventData.java | 9 +- .../rest/types/AuditEventHttpInfo.java | 9 +- .../rest/types/DeidentifiedFileOutput.java | 9 +- .../rest/types/DeidentifyFileResponse.java | 9 +- .../rest/types/DeidentifyStringResponse.java | 15 +- .../rest/types/DetectGuardrailsResponse.java | 11 +- .../rest/types/DetectRunsResponse.java | 15 +- .../generated/rest/types/ErrorResponse.java | 10 +- .../rest/types/ErrorResponseError.java | 15 +- .../generated/rest/types/FileData.java | 10 +- .../rest/types/FileDataDeidentifyAudio.java | 10 +- .../types/FileDataDeidentifyDocument.java | 10 +- .../rest/types/FileDataDeidentifyImage.java | 10 +- .../rest/types/FileDataDeidentifyPdf.java | 10 +- .../types/FileDataDeidentifyPresentation.java | 10 +- .../types/FileDataDeidentifySpreadsheet.java | 10 +- .../FileDataDeidentifyStructuredText.java | 10 +- .../rest/types/FileDataDeidentifyText.java | 10 +- .../rest/types/FileDataReidentifyFile.java | 10 +- .../skyflow/generated/rest/types/Format.java | 15 +- .../generated/rest/types/GooglerpcStatus.java | 15 +- .../rest/types/IdentifyResponse.java | 10 +- .../generated/rest/types/Locations.java | 9 +- .../generated/rest/types/ProtobufAny.java | 9 +- .../rest/types/ReidentifiedFileOutput.java | 9 +- .../rest/types/ReidentifyFileResponse.java | 9 +- .../generated/rest/types/ShiftDates.java | 15 +- .../rest/types/StringResponseEntities.java | 9 +- .../rest/types/TokenTypeMapping.java | 15 +- .../generated/rest/types/Transformations.java | 9 +- .../rest/types/UploadFileV2Response.java | 9 +- .../rest/types/V1AuditAfterOptions.java | 9 +- .../rest/types/V1AuditEventResponse.java | 9 +- .../generated/rest/types/V1AuditResponse.java | 15 +- .../rest/types/V1AuditResponseEvent.java | 15 +- .../types/V1AuditResponseEventRequest.java | 15 +- .../rest/types/V1BatchOperationResponse.java | 15 +- .../generated/rest/types/V1BatchRecord.java | 9 +- .../rest/types/V1BinListResponse.java | 15 +- .../types/V1BulkDeleteRecordResponse.java | 15 +- .../rest/types/V1BulkGetRecordResponse.java | 15 +- .../skyflow/generated/rest/types/V1Card.java | 9 +- .../rest/types/V1DeleteFileResponse.java | 9 +- .../rest/types/V1DeleteRecordResponse.java | 9 +- .../rest/types/V1DetokenizeRecordRequest.java | 9 +- .../types/V1DetokenizeRecordResponse.java | 9 +- .../rest/types/V1DetokenizeResponse.java | 15 +- .../generated/rest/types/V1FieldRecords.java | 9 +- .../rest/types/V1GetAuthTokenResponse.java | 125 ------- .../types/V1GetFileScanStatusResponse.java | 9 +- .../rest/types/V1GetQueryResponse.java | 15 +- .../rest/types/V1InsertRecordResponse.java | 15 +- .../rest/types/V1RecordMetaProperties.java | 9 +- .../rest/types/V1TokenizeRecordRequest.java | 9 +- .../rest/types/V1TokenizeRecordResponse.java | 9 +- .../rest/types/V1TokenizeResponse.java | 15 +- .../rest/types/V1UpdateRecordResponse.java | 9 +- .../rest/types/V1VaultFieldMapping.java | 9 +- .../rest/types/V1VaultSchemaConfig.java | 9 +- .../rest/types/WordCharacterCount.java | 9 +- .../main/java/com/skyflow/logs/ErrorLogs.java | 148 -------- .../main/java/com/skyflow/logs/InfoLogs.java | 120 ------- .../skyflow/vault/data/InsertResponse.java | 22 +- .../skyflow/vault/tokens/DetokenizeData.java | 12 +- .../tokens/DetokenizeRecordResponse.java | 23 +- .../test/java/com/skyflow/SkyflowTests.java | 310 ---------------- .../com/skyflow/VaultClientDotenvTests.java | 104 ------ .../java/com/skyflow/VaultClientTests.java | 122 +------ .../com/skyflow/config/VaultConfigTests.java | 16 +- .../java/com/skyflow/utils/UtilsTests.java | 125 ------- 171 files changed, 2728 insertions(+), 1631 deletions(-) create mode 100644 .github/workflows/flowvault-internal-release.yml create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseDetokenizeData.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRecordResponse.java create mode 100644 common/src/test/java/com/skyflow/BaseSkyflowTests.java create mode 100644 common/src/test/java/com/skyflow/BaseVaultClientTests.java create mode 100644 common/src/test/java/com/skyflow/config/BaseVaultConfigTests.java rename {v2 => common}/src/test/java/com/skyflow/config/CredentialsTests.java (89%) rename {v2 => common}/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java (100%) rename {v2 => common}/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java (95%) rename {v2 => common}/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java (94%) rename {v2 => common}/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java (94%) create mode 100644 common/src/test/java/com/skyflow/utils/BaseUtilsTests.java rename {v2 => common}/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java (100%) rename {v2 => common}/src/test/resources/invalidPrivateKeyCredentials.json (100%) rename {v2 => common}/src/test/resources/invalidTokenURICredentials.json (100%) rename {v2 => common}/src/test/resources/noClientIDCredentials.json (100%) rename {v2 => common}/src/test/resources/noKeyIDCredentials.json (100%) rename {v2 => common}/src/test/resources/noPrivateKeyCredentials.json (100%) rename {v2 => common}/src/test/resources/noTokenURICredentials.json (100%) create mode 100644 common/src/test/resources/notJson.txt create mode 100644 flowvault/src/main/java/com/skyflow/enums/InterfaceName.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DetokenizeData.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRecordResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenGroupRedactions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java delete mode 100644 v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java delete mode 100644 v2/src/main/java/com/skyflow/logs/ErrorLogs.java delete mode 100644 v2/src/main/java/com/skyflow/logs/InfoLogs.java delete mode 100644 v2/src/test/java/com/skyflow/VaultClientDotenvTests.java diff --git a/.github/workflows/flowvault-internal-release.yml b/.github/workflows/flowvault-internal-release.yml new file mode 100644 index 00000000..b1e65c12 --- /dev/null +++ b/.github/workflows/flowvault-internal-release.yml @@ -0,0 +1,27 @@ +name: Publish v3 module to the JFROG Artifactory +on: + push: + tags-ignore: + - '*.*' + paths-ignore: + - "*.md" + branches: + - v3-release/* + +jobs: + build-and-deploy-v3: + uses: ./.github/workflows/shared-build-and-deploy.yml + with: + ref: ${{ github.ref_name }} + server-id: central + profile: jfrog + tag: 'internal' + module: 'flowvault' + secrets: + server-username: ${{ secrets.ARTIFACTORY_USERNAME }} + server-password: ${{ secrets.ARTIFACTORY_PASSWORD }} + gpg-key: ${{ secrets.JFROG_GPG_KEY }} + gpg-passphrase: ${{ secrets.JFROG_GPG_PASSPHRASE }} + skyflow-credentials: ${{ secrets.SKYFLOW_CREDENTIALS }} + test-expired-token: ${{ secrets.TEST_EXPIRED_TOKEN }} + test-reusable-token: ${{ secrets.TEST_REUSABLE_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/shared-build-and-deploy.yml b/.github/workflows/shared-build-and-deploy.yml index 13fd1b5b..9d885190 100644 --- a/.github/workflows/shared-build-and-deploy.yml +++ b/.github/workflows/shared-build-and-deploy.yml @@ -21,6 +21,13 @@ on: description: 'Release Tag' required: true type: string + + module: + description: 'Module to build and publish' + required: false + type: string + default: '' + secrets: server-username: required: true @@ -57,10 +64,10 @@ jobs: java-version: "11" distribution: "adopt" server-id: ${{ inputs.server-id }} - server-username: SERVER_USERNAME - server-password: SERVER_PASSWORD + server-username: ${{ secrets.server-username }} + server-password: ${{ secrets.server-password }} gpg-private-key: ${{ secrets.gpg-key }} # Value of the GPG private key to import - gpg-passphrase: GPG_PASSPHRASE # env variable for GPG private key passphrase + gpg-passphrase: ${{ secrets.gpg-passphrase }} # env variable for GPG private key passphrase - name: Resolve Branch for the Tagged Commit id: resolve-branch @@ -87,7 +94,7 @@ jobs: if ${{ inputs.tag == 'internal' }}; then ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "$(git rev-parse --short "$GITHUB_SHA")" else - ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" + ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "" "${{ inputs.module }}" fi - name: Commit changes @@ -99,7 +106,7 @@ jobs: git checkout ${{ env.branch_name }} fi - git add pom.xml + git add flowvault/pom.xml if [[ "${{ inputs.tag }}" == "internal" ]]; then git commit -m "[AUTOMATED] Private Release ${{ steps.previoustag.outputs.tag }}-dev-$(git rev-parse --short $GITHUB_SHA)" git push origin ${{ github.ref_name }} -f @@ -125,7 +132,12 @@ jobs: json: ${{ secrets.TEST_CREDENTIALS_FILE_STRING }} - name: Publish package - run: mvn --batch-mode deploy -P ${{ inputs.profile }} + run: | + if [[ "${{ inputs.tag }}" == "internal" ]]; then + mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P jfrog -DskipTests + elif [[ "${{ inputs.tag }}" == "beta" || "${{ inputs.tag }}" == "public" ]]; then + mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P ${{ inputs.profile }} -DskipTests + fi env: SERVER_USERNAME: ${{ secrets.server-username }} diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java index 97f19a80..2daff37b 100644 --- a/common/src/main/java/com/skyflow/BaseSkyflow.java +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -1,5 +1,6 @@ package com.skyflow; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.config.Credentials; import com.skyflow.enums.LogLevel; import com.skyflow.errors.ErrorCode; @@ -15,7 +16,7 @@ import java.util.Map; -abstract class BaseSkyflow implements ISkyflow { +abstract class BaseSkyflow implements ISkyflow { protected final BaseSkyflowClientBuilder builder; protected BaseSkyflow(BaseSkyflowClientBuilder builder) { @@ -72,7 +73,7 @@ protected static T resolveOrThrow(Map map, String key, return value; } - abstract static class BaseSkyflowClientBuilder { + abstract static class BaseSkyflowClientBuilder { protected final LinkedHashMap vaultConfigMap = new LinkedHashMap<>(); protected final LinkedHashMap vaultClientsMap = new LinkedHashMap<>(); protected Credentials skyflowCredentials; @@ -164,11 +165,35 @@ protected final void addSkyflowCredentialsTemplate(Credentials credentials) thro protected abstract void validateVaultConfig(V vaultConfig) throws SkyflowException; - protected abstract V cloneVaultConfig(V vaultConfig); + @SuppressWarnings("unchecked") + protected final V cloneVaultConfig(V vaultConfig) { + try { + return (V) vaultConfig.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } - protected abstract String extractVaultId(V vaultConfig); + protected final String extractVaultId(V vaultConfig) { + return vaultConfig.getVaultId(); + } - protected abstract V mergeVaultConfig(V incoming, V existing); + protected final V mergeVaultConfig(V incoming, V existing) { + if (incoming.getEnv() != null) { + existing.setEnv(incoming.getEnv()); + } + if (incoming.getClusterId() != null) { + existing.setClusterId(incoming.getClusterId()); + } + if (incoming.getCredentials() != null) { + try { + existing.setCredentials((Credentials) incoming.getCredentials().clone()); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + return existing; + } protected abstract void onVaultConfigAdded(V vaultConfig) throws SkyflowException; diff --git a/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeData.java b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeData.java new file mode 100644 index 00000000..0da23763 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeData.java @@ -0,0 +1,14 @@ +package com.skyflow.vault.data; + +public class BaseDetokenizeData { + private final String token; + + public BaseDetokenizeData(String token) { + this.token = token; + } + + public String getToken() { + return this.token; + } + +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRecordResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRecordResponse.java new file mode 100644 index 00000000..7a1ec217 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeRecordResponse.java @@ -0,0 +1,19 @@ +package com.skyflow.vault.data; + +public class BaseDetokenizeRecordResponse { + private final String token; + private final String error; + + public BaseDetokenizeRecordResponse(String token, String error){ + this.token = token; + this.error = error; + } + public String getToken() { + return token; + } + + public String getError() { + return error; + } + +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java index ad158145..a5061b25 100644 --- a/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java +++ b/common/src/main/java/com/skyflow/vault/data/BaseDetokenizeResponse.java @@ -1,4 +1,5 @@ package com.skyflow.vault.data; public class BaseDetokenizeResponse { + } diff --git a/common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java index 7b5efb9b..84196bf7 100644 --- a/common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java +++ b/common/src/main/java/com/skyflow/vault/data/BaseInsertResponse.java @@ -1,4 +1,31 @@ package com.skyflow.vault.data; +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.HashMap; + public class BaseInsertResponse { + private final ArrayList> insertedFields; + private final ArrayList> errors; + + public BaseInsertResponse(ArrayList> insertedFields, ArrayList> errors) { + this.insertedFields = insertedFields; + this.errors = errors; + } + + public ArrayList> getInsertedFields() { + return insertedFields; + } + + public ArrayList> getErrors() { + return errors; + } + + @Override + public String toString() { + Gson gson = new Gson().newBuilder().serializeNulls().create(); + return gson.toJson(this); + } } + diff --git a/common/src/test/java/com/skyflow/BaseSkyflowTests.java b/common/src/test/java/com/skyflow/BaseSkyflowTests.java new file mode 100644 index 00000000..57c72a83 --- /dev/null +++ b/common/src/test/java/com/skyflow/BaseSkyflowTests.java @@ -0,0 +1,340 @@ +package com.skyflow; + +import com.skyflow.config.BaseVaultConfig; +import com.skyflow.config.Credentials; +import com.skyflow.enums.Env; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class BaseSkyflowTests { + private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; + private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static String vaultID = null; + private static String clusterID = null; + private static String newClusterID = null; + private static String token = null; + + @BeforeClass + public static void setup() { + vaultID = "test_vault_id"; + clusterID = "test_cluster_id"; + newClusterID = "new_test_cluster_id"; + token = "test_token"; + } + + private static BaseVaultConfig newConfig(String vaultId, String clusterId, Env env) { + BaseVaultConfig config = new BaseVaultConfig(); + config.setVaultId(vaultId); + config.setClusterId(clusterId); + config.setEnv(env); + return config; + } + + @Test + public void testAddingExistingVaultConfigThrows() { + try { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder().build(); + client.addVaultConfig(config).addVaultConfig(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.VaultIdAlreadyInConfigList.getMessage(), e.getMessage()); + } + } + + @Test + public void testUpdatingNonExistentVaultConfigInBuilderThrows() { + try { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + TestSkyflow.builder().updateVaultConfig(config).build(); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); + } + } + + @Test + public void testUpdatingNonExistentVaultConfigInClientThrows() { + try { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder().build(); + client.updateVaultConfig(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); + } + } + + @Test + public void testRemovingNonExistentVaultConfigInBuilderThrows() { + try { + TestSkyflow.builder().removeVaultConfig(vaultID).build(); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); + } + } + + @Test + public void testRemovingExistingVaultConfigSucceeds() { + try { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(config).build(); + client.removeVaultConfig(vaultID); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testRemovingVaultConfigWithoutAddingThrows() { + try { + TestSkyflow client = TestSkyflow.builder().build(); + client.removeVaultConfig(vaultID); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); + } + } + + @Test + public void testGettingNonExistentVaultConfigReturnsNull() { + TestSkyflow client = TestSkyflow.builder().build(); + Assert.assertNull(client.getVaultConfig(vaultID)); + } + + @Test + public void testVaultThrowsWhenNoConfigAdded() { + try { + TestSkyflow client = TestSkyflow.builder().build(); + client.vault(); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); + } + } + + @Test + public void testVaultByIdThrowsAfterRemoval() { + try { + BaseVaultConfig primary = newConfig(vaultID, clusterID, Env.SANDBOX); + BaseVaultConfig secondary = newConfig(vaultID + "123", clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(primary).addVaultConfig(secondary).build(); + client.removeVaultConfig(vaultID); + client.vault(vaultID); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); + } + } + + @Test + public void testDefaultLogLevel() { + TestSkyflow client = TestSkyflow.builder().setLogLevel(null).build(); + Assert.assertEquals(LogLevel.ERROR, client.getLogLevel()); + } + + @Test + public void testSetLogLevel() { + TestSkyflow client = TestSkyflow.builder().setLogLevel(LogLevel.INFO).build(); + Assert.assertEquals(LogLevel.INFO, client.getLogLevel()); + client.setLogLevel(LogLevel.WARN); + Assert.assertEquals(LogLevel.WARN, client.getLogLevel()); + } + + @Test + public void testAddingInvalidSkyflowCredentialsThrows() { + try { + Credentials credentials = new Credentials(); + TestSkyflow.builder().addSkyflowCredentials(credentials).build(); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.NoTokenGenerationMeansPassed.getMessage(), e.getMessage()); + } + } + + @Test + public void testUpdatingValidSkyflowCredentialsSucceeds() { + try { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + Credentials credentials = new Credentials(); + credentials.setToken(token); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(config).build(); + client.updateSkyflowCredentials(credentials); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testUpdateVaultConfigNullCredentialsFallsBackToPrevious() { + try { + Credentials creds = new Credentials(); + creds.setToken(token); + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + config.setCredentials(creds); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(config).build(); + + BaseVaultConfig partialUpdate = newConfig(vaultID, clusterID, Env.SANDBOX); + client.updateVaultConfig(partialUpdate); + Assert.assertNotNull(client.getVaultConfig(vaultID).getCredentials()); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testUpdateVaultConfigWithNewClusterIdAndCredentialsUpdatesAllFields() { + try { + Credentials creds = new Credentials(); + creds.setToken(token); + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.DEV); + config.setCredentials(creds); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(config).build(); + + Credentials newCreds = new Credentials(); + newCreds.setToken("updated-token-value"); + BaseVaultConfig update = newConfig(vaultID, newClusterID, Env.PROD); + update.setCredentials(newCreds); + client.updateVaultConfig(update); + + Assert.assertEquals(newClusterID, client.getVaultConfig(vaultID).getClusterId()); + Assert.assertEquals(Env.PROD, client.getVaultConfig(vaultID).getEnv()); + Assert.assertEquals("updated-token-value", client.getVaultConfig(vaultID).getCredentials().getToken()); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testUpdateVaultConfigWithNullEnvFallsBackToPreviousEnv() { + // BaseVaultConfig's setEnv/constructor never store null (default to PROD), so getEnv() + // never returns null via the normal API. Override it to exercise the fallback branch + // in mergeVaultConfig. + try { + Credentials creds = new Credentials(); + creds.setToken(token); + BaseVaultConfig initial = newConfig(vaultID, clusterID, Env.SANDBOX); + initial.setCredentials(creds); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(initial).build(); + + BaseVaultConfig updateWithNullEnv = new BaseVaultConfig() { + @Override + public Env getEnv() { + return null; + } + }; + updateWithNullEnv.setVaultId(vaultID); + updateWithNullEnv.setClusterId(clusterID); + updateWithNullEnv.setCredentials(creds); + + client.updateVaultConfig(updateWithNullEnv); + Assert.assertEquals(Env.SANDBOX, client.getVaultConfig(vaultID).getEnv()); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testMergeVaultConfigWithNullClusterIdFallsBackToPreviousClusterId() { + BaseVaultConfig existing = newConfig(vaultID, clusterID, Env.DEV); + BaseVaultConfig incoming = new BaseVaultConfig(); + incoming.setVaultId(vaultID); + // clusterId intentionally left null + + BaseVaultConfig result = TestSkyflow.builder().mergeVaultConfig(incoming, existing); + Assert.assertEquals(clusterID, result.getClusterId()); + } + + private static class TestSkyflow extends BaseSkyflow { + private TestSkyflow(TestSkyflowClientBuilder builder) { + super(builder); + } + + static TestSkyflowClientBuilder builder() { + return new TestSkyflowClientBuilder(); + } + + @Override + protected TestSkyflow self() { + return this; + } + + Object vault(String vaultId) throws SkyflowException { + return resolveOrThrow(this.builder.vaultClientsMap, vaultId, + ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); + } + + private static class TestSkyflowClientBuilder extends BaseSkyflowClientBuilder { + @Override + protected void validateVaultConfig(BaseVaultConfig vaultConfig) throws SkyflowException { + if (vaultConfig.getVaultId() == null || vaultConfig.getVaultId().trim().isEmpty()) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyVaultId.getMessage()); + } + } + + @Override + protected void onVaultConfigAdded(BaseVaultConfig vaultConfig) { + this.vaultClientsMap.put(vaultConfig.getVaultId(), new Object()); + } + + @Override + protected void onVaultConfigUpdated(BaseVaultConfig updatedConfig) { + this.vaultClientsMap.put(updatedConfig.getVaultId(), new Object()); + } + + @Override + protected void onCredentialsUpdated(Credentials credentials) { + // no-op: this test double only exercises template orchestration, not propagation + } + + @Override + public TestSkyflowClientBuilder addVaultConfig(BaseVaultConfig vaultConfig) throws SkyflowException { + super.addVaultConfig(vaultConfig); + return this; + } + + @Override + public TestSkyflowClientBuilder updateVaultConfig(BaseVaultConfig vaultConfig) throws SkyflowException { + super.updateVaultConfig(vaultConfig); + return this; + } + + @Override + public TestSkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { + super.removeVaultConfig(vaultId); + return this; + } + + @Override + public TestSkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { + super.addSkyflowCredentials(credentials); + return this; + } + + @Override + public TestSkyflowClientBuilder setLogLevel(LogLevel logLevel) { + super.setLogLevel(logLevel); + return this; + } + + TestSkyflow build() { + return new TestSkyflow(this); + } + } + } +} diff --git a/common/src/test/java/com/skyflow/BaseVaultClientTests.java b/common/src/test/java/com/skyflow/BaseVaultClientTests.java new file mode 100644 index 00000000..e5a12687 --- /dev/null +++ b/common/src/test/java/com/skyflow/BaseVaultClientTests.java @@ -0,0 +1,165 @@ +package com.skyflow; + +import com.skyflow.config.BaseCredentials; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import com.skyflow.utils.BaseConstants; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class BaseVaultClientTests { + + private static final String ENV_FILE = ".env"; + private byte[] originalEnvContent; + + @Before + public void saveEnvFileState() throws IOException { + File f = new File(ENV_FILE); + originalEnvContent = f.exists() ? Files.readAllBytes(Paths.get(ENV_FILE)) : null; + } + + @After + public void restoreEnvFile() throws IOException { + if (originalEnvContent != null) { + Files.write(Paths.get(ENV_FILE), originalEnvContent); + } else { + Files.deleteIfExists(Paths.get(ENV_FILE)); + } + } + + private BaseVaultClient newClient(BaseCredentials commonCredentials) { + return new BaseVaultClient<>(new Object(), commonCredentials); + } + + @Test + public void testPrioritiseCredentials_prefersVaultSpecificCredentials() throws SkyflowException { + BaseCredentials vaultSpecific = new BaseCredentials(); + vaultSpecific.setApiKey("test_api_key"); + BaseVaultClient client = newClient(null); + + client.prioritiseCredentials(vaultSpecific); + + Assert.assertEquals(vaultSpecific, client.finalCredentials); + } + + @Test + public void testPrioritiseCredentials_fallsBackToCommonCredentials() throws SkyflowException { + BaseCredentials common = new BaseCredentials(); + common.setApiKey("common_api_key"); + BaseVaultClient client = newClient(common); + + client.prioritiseCredentials(null); + + Assert.assertEquals(common, client.finalCredentials); + } + + @Test + public void testPrioritiseCredentials_credentialChange_resetsTokenAndApiKey() throws SkyflowException { + BaseCredentials credentialsA = new BaseCredentials(); + credentialsA.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); + BaseVaultClient client = newClient(null); + + client.prioritiseCredentials(credentialsA); + client.token = "cached-token"; + client.apiKey = "cached-api-key"; + + BaseCredentials credentialsB = new BaseCredentials(); + credentialsB.setToken("other-token"); + client.prioritiseCredentials(credentialsB); + + Assert.assertNull(client.token); + Assert.assertNull(client.apiKey); + } + + @Test + public void testSetBearerToken_withApiKey() throws SkyflowException { + BaseCredentials creds = new BaseCredentials(); + creds.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + BaseVaultClient client = newClient(null); + + client.setBearerToken(creds); + + Assert.assertEquals("sky-ab123-abcd1234cdef1234abcd4321cdef4321", client.token); + } + + @Test + public void testSetBearerToken_generatesTokenWhenNull() throws SkyflowException { + BaseCredentials creds = new BaseCredentials(); + creds.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); + BaseVaultClient client = newClient(null); + + client.setBearerToken(creds); + + Assert.assertEquals("x.eyJleHAiOjk5OTk5OTk5OTl9.y", client.token); + } + + @Test + public void testSetBearerToken_reusesValidNonExpiredToken() throws SkyflowException { + BaseCredentials creds = new BaseCredentials(); + creds.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); + BaseVaultClient client = newClient(null); + + // First call: token=null → generates from creds.getToken() + client.setBearerToken(creds); + Assert.assertEquals("x.eyJleHAiOjk5OTk5OTk5OTl9.y", client.token); + + // Second call: token valid, not expired → reuse branch + client.setBearerToken(creds); + Assert.assertEquals("x.eyJleHAiOjk5OTk5OTk5OTl9.y", client.token); + } + + @Test + public void testSetBearerToken_noCredentials_throwsEmptyCredentials() { + BaseVaultClient client = newClient(null); + try { + client.setBearerToken(null); + Assert.fail("Should have thrown SkyflowException"); + } catch (SkyflowException e) { + // message varies by environment (EmptyCredentials when no .env, or credential error when .env provides creds) + } + } + + /** + * Covers the dotenv success path: Dotenv.load() succeeds and returns a + * non-null credentials string, so finalCredentials is set via credentialsString. + */ + @Test + public void testPrioritiseCredentials_dotenvReturnsCredentials_setsCredentials() throws Exception { + try (FileWriter fw = new FileWriter(ENV_FILE)) { + fw.write(BaseConstants.ENV_CREDENTIALS_KEY_NAME + "={\"token\":\"env-token-value\"}\n"); + } + + BaseVaultClient client = newClient(null); + client.prioritiseCredentials(null); + + Assert.assertNotNull(client.finalCredentials); + Assert.assertEquals("{\"token\":\"env-token-value\"}", client.finalCredentials.getCredentialsString()); + } + + /** + * Covers the path where dotenv loads but the key is absent (returns null), + * causing SkyflowException(EmptyCredentials) to be thrown directly. + */ + @Test + public void testPrioritiseCredentials_dotenvKeyMissing_throwsSkyflowException() throws Exception { + try (FileWriter fw = new FileWriter(ENV_FILE)) { + fw.write("SOME_OTHER_KEY=some_value\n"); + } + + BaseVaultClient client = newClient(null); + try { + client.prioritiseCredentials(null); + Assert.fail("Should have thrown SkyflowException"); + } catch (SkyflowException e) { + Assert.assertTrue(e.getMessage().contains(ErrorMessage.EmptyCredentials.getMessage())); + } + } +} diff --git a/common/src/test/java/com/skyflow/config/BaseVaultConfigTests.java b/common/src/test/java/com/skyflow/config/BaseVaultConfigTests.java new file mode 100644 index 00000000..bea158b5 --- /dev/null +++ b/common/src/test/java/com/skyflow/config/BaseVaultConfigTests.java @@ -0,0 +1,75 @@ +package com.skyflow.config; + +import com.skyflow.enums.Env; +import org.junit.Assert; +import org.junit.Test; + +public class BaseVaultConfigTests { + + @Test + public void testDefaultConstructorDefaults() { + BaseVaultConfig config = new BaseVaultConfig(); + Assert.assertNull(config.getVaultId()); + Assert.assertNull(config.getClusterId()); + Assert.assertEquals(Env.PROD, config.getEnv()); + Assert.assertNull(config.getCredentials()); + } + + @Test + public void testGettersAndSetters() { + BaseVaultConfig config = new BaseVaultConfig(); + Credentials credentials = new Credentials(); + credentials.setToken("test_token"); + + config.setVaultId("vault_id"); + config.setClusterId("cluster_id"); + config.setEnv(Env.SANDBOX); + config.setCredentials(credentials); + + Assert.assertEquals("vault_id", config.getVaultId()); + Assert.assertEquals("cluster_id", config.getClusterId()); + Assert.assertEquals(Env.SANDBOX, config.getEnv()); + Assert.assertEquals(credentials, config.getCredentials()); + } + + @Test + public void testSetEnvNullFallsBackToProd() { + BaseVaultConfig config = new BaseVaultConfig(); + config.setEnv(Env.DEV); + config.setEnv(null); + Assert.assertEquals(Env.PROD, config.getEnv()); + } + + @Test + public void testCloneProducesIndependentCopy() throws CloneNotSupportedException { + BaseVaultConfig original = new BaseVaultConfig(); + original.setVaultId("vault_id"); + original.setClusterId("cluster_id"); + original.setEnv(Env.STAGE); + Credentials credentials = new Credentials(); + credentials.setToken("original_token"); + original.setCredentials(credentials); + + BaseVaultConfig cloned = (BaseVaultConfig) original.clone(); + + Assert.assertNotSame(original, cloned); + Assert.assertEquals(original.getVaultId(), cloned.getVaultId()); + Assert.assertEquals(original.getClusterId(), cloned.getClusterId()); + Assert.assertEquals(original.getEnv(), cloned.getEnv()); + Assert.assertNotSame(original.getCredentials(), cloned.getCredentials()); + Assert.assertEquals("original_token", cloned.getCredentials().getToken()); + + // Mutating the clone's credentials must not affect the original + cloned.getCredentials().setToken("mutated_token"); + Assert.assertEquals("original_token", original.getCredentials().getToken()); + } + + @Test + public void testCloneWithNullCredentials() throws CloneNotSupportedException { + BaseVaultConfig original = new BaseVaultConfig(); + original.setVaultId("vault_id"); + + BaseVaultConfig cloned = (BaseVaultConfig) original.clone(); + Assert.assertNull(cloned.getCredentials()); + } +} diff --git a/v2/src/test/java/com/skyflow/config/CredentialsTests.java b/common/src/test/java/com/skyflow/config/CredentialsTests.java similarity index 89% rename from v2/src/test/java/com/skyflow/config/CredentialsTests.java rename to common/src/test/java/com/skyflow/config/CredentialsTests.java index a9a9153f..cdf7fc3f 100644 --- a/v2/src/test/java/com/skyflow/config/CredentialsTests.java +++ b/common/src/test/java/com/skyflow/config/CredentialsTests.java @@ -3,7 +3,7 @@ import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; -import com.skyflow.utils.validations.Validations; +import com.skyflow.utils.validations.BaseValidations; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; @@ -13,8 +13,6 @@ import java.util.HashMap; import java.util.Map; -import com.skyflow.utils.Utils; - public class CredentialsTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; @@ -49,7 +47,7 @@ public void testValidCredentialsWithPath() { try { Credentials credentials = new Credentials(); credentials.setPath(path); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.assertNull(credentials.getCredentialsString()); Assert.assertNull(credentials.getToken()); Assert.assertNull(credentials.getApiKey()); @@ -63,7 +61,7 @@ public void testValidCredentialsWithCredentialsString() { try { Credentials credentials = new Credentials(); credentials.setCredentialsString(credentialsString); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.assertNull(credentials.getPath()); Assert.assertNull(credentials.getToken()); Assert.assertNull(credentials.getApiKey()); @@ -77,7 +75,7 @@ public void testValidCredentialsWithToken() { try { Credentials credentials = new Credentials(); credentials.setToken(token); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.assertNull(credentials.getPath()); Assert.assertNull(credentials.getCredentialsString()); Assert.assertNull(credentials.getApiKey()); @@ -91,7 +89,7 @@ public void testValidCredentialsWithApikey() { try { Credentials credentials = new Credentials(); credentials.setApiKey(validApiKey); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.assertNull(credentials.getPath()); Assert.assertNull(credentials.getCredentialsString()); Assert.assertNull(credentials.getToken()); @@ -108,7 +106,7 @@ public void testValidCredentialsWithRolesAndContext() { credentials.setApiKey(validApiKey); credentials.setRoles(roles); credentials.setContext(context); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.assertNull(credentials.getPath()); Assert.assertNull(credentials.getCredentialsString()); Assert.assertNull(credentials.getToken()); @@ -124,7 +122,7 @@ public void testEmptyPathInCredentials() { try { Credentials credentials = new Credentials(); credentials.setPath(""); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -137,7 +135,7 @@ public void testEmptyCredentialsStringInCredentials() { try { Credentials credentials = new Credentials(); credentials.setCredentialsString(""); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -150,7 +148,7 @@ public void testEmptyTokenInCredentials() { try { Credentials credentials = new Credentials(); credentials.setToken(""); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -163,7 +161,7 @@ public void testEmptyApikeyInCredentials() { try { Credentials credentials = new Credentials(); credentials.setApiKey(""); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -176,7 +174,7 @@ public void testInvalidApikeyInCredentials() { try { Credentials credentials = new Credentials(); credentials.setApiKey(invalidApiKey); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -190,7 +188,7 @@ public void testBothTokenAndPathInCredentials() { Credentials credentials = new Credentials(); credentials.setPath(path); credentials.setToken(token); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -202,7 +200,7 @@ public void testBothTokenAndPathInCredentials() { public void testNothingPassedInCredentials() { try { Credentials credentials = new Credentials(); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -216,7 +214,7 @@ public void testEmptyRolesInCredentials() { Credentials credentials = new Credentials(); credentials.setPath(path); credentials.setRoles(roles); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -232,7 +230,7 @@ public void testNullRoleInRolesInCredentials() { roles.add(role); roles.add(null); credentials.setRoles(roles); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -248,7 +246,7 @@ public void testEmptyRoleInRolesInCredentials() { roles.add(role); roles.add(""); credentials.setRoles(roles); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -262,7 +260,7 @@ public void testEmptyContextInCredentials() { Credentials credentials = new Credentials(); credentials.setPath(path); credentials.setContext(""); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -280,7 +278,7 @@ public void testValidMapContextInCredentials() { ctxMap.put("department", "finance"); ctxMap.put("user_id", "user_12345"); credentials.setContext(ctxMap); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); } catch (SkyflowException e) { Assert.fail(INVALID_EXCEPTION_THROWN); } @@ -293,7 +291,7 @@ public void testEmptyMapContextInCredentials() { credentials.setPath(path); Map ctxMap = new HashMap<>(); credentials.setContext(ctxMap); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -310,7 +308,7 @@ public void testInvalidMapKeyInContextCredentials() { ctxMap.put("valid_key", "value"); ctxMap.put("invalid-key", "value"); credentials.setContext(ctxMap); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); @@ -329,7 +327,7 @@ public void testMapContextWithNestedObjects() { ctxMap.put("role", "admin"); ctxMap.put("metadata", nested); credentials.setContext(ctxMap); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); } catch (SkyflowException e) { Assert.fail(INVALID_EXCEPTION_THROWN); } @@ -346,7 +344,7 @@ public void testMapContextWithMixedValueTypes() { ctxMap.put("active", true); ctxMap.put("timestamp", "2025-12-25T10:30:00Z"); credentials.setContext(ctxMap); - Validations.validateCredentials(credentials); + BaseValidations.validateCredentials(credentials); } catch (SkyflowException e) { Assert.fail(INVALID_EXCEPTION_THROWN); } diff --git a/v2/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java b/common/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java similarity index 100% rename from v2/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java rename to common/src/test/java/com/skyflow/errors/SkyflowExceptionTest.java diff --git a/v2/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java b/common/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java similarity index 95% rename from v2/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java rename to common/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java index 3aeca811..bc8f09b5 100644 --- a/v2/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java +++ b/common/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java @@ -3,8 +3,8 @@ import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; -import com.skyflow.utils.Constants; -import com.skyflow.utils.Utils; +import com.skyflow.utils.BaseConstants; +import com.skyflow.utils.BaseUtils; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -92,7 +92,7 @@ public void testEmptyCredentialsFilePath() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), ""), e.getMessage() + BaseUtils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), ""), e.getMessage() ); } } @@ -107,7 +107,7 @@ public void testInvalidFilePath() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), invalidFilePath), + BaseUtils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), invalidFilePath), e.getMessage() ); } @@ -123,7 +123,7 @@ public void testInvalidCredentialsFile() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.FileInvalidJson.getMessage(), invalidJsonFilePath), + BaseUtils.parameterizedString(ErrorMessage.FileInvalidJson.getMessage(), invalidJsonFilePath), e.getMessage() ); } @@ -264,7 +264,7 @@ public void testBearerTokenWithNewFormCredentialKeys() { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); // InvalidKeySpec confirms all credential fields were resolved — failure is at RSA parsing, not field lookup Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.InvalidKeySpec.getMessage(), Constants.SDK_PREFIX), + BaseUtils.parameterizedString(ErrorMessage.InvalidKeySpec.getMessage(), BaseConstants.SDK_PREFIX), e.getMessage()); } } diff --git a/v2/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java b/common/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java similarity index 94% rename from v2/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java rename to common/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java index 93d69b0e..1465c2ca 100644 --- a/v2/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java +++ b/common/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java @@ -3,7 +3,7 @@ import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; -import com.skyflow.utils.Utils; +import com.skyflow.utils.BaseUtils; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -85,7 +85,7 @@ public void testEmptyCredentialsFilePath() { Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(Utils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), ""), e.getMessage()); + Assert.assertEquals(BaseUtils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), ""), e.getMessage()); } } @@ -99,7 +99,7 @@ public void testInvalidFilePath() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), invalidFilePath), + BaseUtils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), invalidFilePath), e.getMessage()); } } @@ -114,7 +114,7 @@ public void testInvalidCredentialsFile() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.FileInvalidJson.getMessage(), invalidJsonFilePath), + BaseUtils.parameterizedString(ErrorMessage.FileInvalidJson.getMessage(), invalidJsonFilePath), e.getMessage() ); } @@ -129,7 +129,7 @@ public void testEmptyCredentialsString() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.InvalidCredentials.getMessage(), invalidJsonFilePath), + BaseUtils.parameterizedString(ErrorMessage.InvalidCredentials.getMessage(), invalidJsonFilePath), e.getMessage() ); } catch (Exception e) { @@ -146,7 +146,7 @@ public void testInvalidCredentialsString() { } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.CredentialsStringInvalidJson.getMessage(), invalidJsonFilePath), + BaseUtils.parameterizedString(ErrorMessage.CredentialsStringInvalidJson.getMessage(), invalidJsonFilePath), e.getMessage() ); } diff --git a/v2/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java b/common/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java similarity index 94% rename from v2/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java rename to common/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java index 88887681..cb631071 100644 --- a/v2/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java +++ b/common/src/test/java/com/skyflow/serviceaccount/util/TokenTests.java @@ -1,7 +1,7 @@ package com.skyflow.serviceaccount.util; -import com.skyflow.Skyflow; import com.skyflow.enums.LogLevel; +import com.skyflow.utils.logger.LogUtil; import io.github.cdimascio.dotenv.Dotenv; import org.junit.Assert; import org.junit.BeforeClass; @@ -12,7 +12,7 @@ public class TokenTests { @BeforeClass public static void setup() { - Skyflow skyflowClient = Skyflow.builder().setLogLevel(LogLevel.DEBUG).build(); + LogUtil.setupLogger(LogLevel.DEBUG); } @Test diff --git a/common/src/test/java/com/skyflow/utils/BaseUtilsTests.java b/common/src/test/java/com/skyflow/utils/BaseUtilsTests.java new file mode 100644 index 00000000..024bca74 --- /dev/null +++ b/common/src/test/java/com/skyflow/utils/BaseUtilsTests.java @@ -0,0 +1,138 @@ +package com.skyflow.utils; + +import com.skyflow.config.Credentials; +import com.skyflow.enums.Env; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.SkyflowException; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; + +public class BaseUtilsTests { + private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; + private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static String clusterId = null; + private static String url = null; + private static String filePath = null; + private static String credentialsString = null; + private static String token = null; + private static String context = null; + private static ArrayList roles = null; + + @BeforeClass + public static void setup() { + clusterId = "test_cluster_id"; + url = "https://test-url.com/java/unit/tests"; + filePath = "invalid/file/path/credentials.json"; + credentialsString = "invalid credentials string"; + token = "invalid-token"; + context = "test_context"; + roles = new ArrayList<>(); + roles.add("test_role"); + } + + @Test + public void testGetVaultURLForDev() { + try { + String vaultURL = BaseUtils.getVaultURL(clusterId, Env.DEV, BaseConstants.V2_VAULT_DOMAIN); + String devUrl = "https://test_cluster_id.vault.skyflowapis.dev"; + Assert.assertEquals(devUrl, vaultURL); + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testGetVaultURLForStage() { + try { + String vaultURL = BaseUtils.getVaultURL(clusterId, Env.STAGE, BaseConstants.V2_VAULT_DOMAIN); + String stageUrl = "https://test_cluster_id.vault.skyflowapis.tech"; + Assert.assertEquals(stageUrl, vaultURL); + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testGetVaultURLForSandbox() { + try { + String vaultURL = BaseUtils.getVaultURL(clusterId, Env.SANDBOX, BaseConstants.V2_VAULT_DOMAIN); + String sandboxUrl = "https://test_cluster_id.vault.skyflowapis-preview.com"; + Assert.assertEquals(sandboxUrl, vaultURL); + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testGetVaultURLForProd() { + try { + String vaultURL = BaseUtils.getVaultURL(clusterId, Env.PROD, BaseConstants.V2_VAULT_DOMAIN); + String prodUrl = "https://test_cluster_id.vault.skyflowapis.com"; + Assert.assertEquals(prodUrl, vaultURL); + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testGetBaseURL() { + try { + String baseURL = BaseUtils.getBaseURL(url); + String expected = "https://test-url.com"; + Assert.assertEquals(expected, baseURL); + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testGenerateBearerTokenWithCredentialsFile() { + try { + Credentials credentials = new Credentials(); + credentials.setPath(filePath); + credentials.setContext(context); + credentials.setRoles(roles); + BaseUtils.generateBearerToken(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals( + BaseUtils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), filePath), + e.getMessage() + ); + } + } + + @Test + public void testGenerateBearerTokenWithCredentialsString() { + try { + Credentials credentials = new Credentials(); + credentials.setCredentialsString(credentialsString); + credentials.setContext(context); + credentials.setRoles(roles); + BaseUtils.generateBearerToken(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.CredentialsStringInvalidJson.getMessage(), e.getMessage()); + } + } + + @Test + public void testGenerateBearerTokenWithToken() { + try { + Credentials credentials = new Credentials(); + credentials.setToken(token); + credentials.setContext(context); + credentials.setRoles(roles); + String bearerToken = BaseUtils.generateBearerToken(credentials); + Assert.assertEquals(token, bearerToken); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } +} diff --git a/v2/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java b/common/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java similarity index 100% rename from v2/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java rename to common/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java diff --git a/v2/src/test/resources/invalidPrivateKeyCredentials.json b/common/src/test/resources/invalidPrivateKeyCredentials.json similarity index 100% rename from v2/src/test/resources/invalidPrivateKeyCredentials.json rename to common/src/test/resources/invalidPrivateKeyCredentials.json diff --git a/v2/src/test/resources/invalidTokenURICredentials.json b/common/src/test/resources/invalidTokenURICredentials.json similarity index 100% rename from v2/src/test/resources/invalidTokenURICredentials.json rename to common/src/test/resources/invalidTokenURICredentials.json diff --git a/v2/src/test/resources/noClientIDCredentials.json b/common/src/test/resources/noClientIDCredentials.json similarity index 100% rename from v2/src/test/resources/noClientIDCredentials.json rename to common/src/test/resources/noClientIDCredentials.json diff --git a/v2/src/test/resources/noKeyIDCredentials.json b/common/src/test/resources/noKeyIDCredentials.json similarity index 100% rename from v2/src/test/resources/noKeyIDCredentials.json rename to common/src/test/resources/noKeyIDCredentials.json diff --git a/v2/src/test/resources/noPrivateKeyCredentials.json b/common/src/test/resources/noPrivateKeyCredentials.json similarity index 100% rename from v2/src/test/resources/noPrivateKeyCredentials.json rename to common/src/test/resources/noPrivateKeyCredentials.json diff --git a/v2/src/test/resources/noTokenURICredentials.json b/common/src/test/resources/noTokenURICredentials.json similarity index 100% rename from v2/src/test/resources/noTokenURICredentials.json rename to common/src/test/resources/noTokenURICredentials.json diff --git a/common/src/test/resources/notJson.txt b/common/src/test/resources/notJson.txt new file mode 100644 index 00000000..bdf08de0 --- /dev/null +++ b/common/src/test/resources/notJson.txt @@ -0,0 +1 @@ +test file \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java index 51ccccd9..bd3c451f 100644 --- a/flowvault/src/main/java/com/skyflow/Skyflow.java +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -34,44 +34,11 @@ public VaultConfig getVaultConfig() { } public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { - @Override protected void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { Validations.validateVaultConfiguration(vaultConfig); } - @Override - protected VaultConfig cloneVaultConfig(VaultConfig vaultConfig) { - try { - return (VaultConfig) vaultConfig.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - @Override - protected String extractVaultId(VaultConfig vaultConfig) { - return vaultConfig.getVaultId(); - } - - @Override - protected VaultConfig mergeVaultConfig(VaultConfig incoming, VaultConfig existing) { - if (incoming.getEnv() != null) { - existing.setEnv(incoming.getEnv()); - } - if (incoming.getClusterId() != null) { - existing.setClusterId(incoming.getClusterId()); - } - if (incoming.getCredentials() != null) { - try { - existing.setCredentials((Credentials) incoming.getCredentials().clone()); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - return existing; - } - @Override protected void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException { this.vaultClientsMap.put(vaultConfig.getVaultId(), new VaultController(vaultConfig, this.skyflowCredentials)); diff --git a/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java b/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java new file mode 100644 index 00000000..1dcf86b6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java @@ -0,0 +1,19 @@ +package com.skyflow.enums; + +public enum InterfaceName { + INSERT("insert"), + DETOKENIZE("detokenize"), + DELETE("delete tokens"), + TOKENIZE("tokenize"); + + + private final String interfaceName; + + InterfaceName(String interfaceName) { + this.interfaceName = interfaceName; + } + + public String getName() { + return interfaceName; + } +} diff --git a/flowvault/src/main/java/com/skyflow/utils/Utils.java b/flowvault/src/main/java/com/skyflow/utils/Utils.java index 207edae6..670aa05b 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Utils.java +++ b/flowvault/src/main/java/com/skyflow/utils/Utils.java @@ -2,16 +2,16 @@ import com.google.gson.JsonObject; import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; +import com.skyflow.enums.UpsertType; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; -import com.skyflow.generated.rest.types.V1InsertRecordData; -import com.skyflow.generated.rest.types.V1InsertResponse; -import com.skyflow.generated.rest.types.V1RecordResponseObject; -import com.skyflow.generated.rest.types.V1TokenGroupRedactions; +import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; +import com.skyflow.generated.rest.types.*; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.serviceaccount.util.BearerToken; @@ -107,5 +107,127 @@ public static String generateBearerToken(Credentials credentials) throws Skyflow } } + public static V1InsertRequest getBulkInsertRequestBody(InsertRequest request, VaultConfig config) { + ArrayList records = request.getRecords(); + List insertRecordDataList = new ArrayList<>(); + for (InsertRecord record : records) { + V1InsertRecordData.Builder data = V1InsertRecordData.builder(); + data.data(record.getData()); + if (record.getTable() != null && !record.getTable().isEmpty()) { + data.tableName(record.getTable()); + } + if (record.getUpsert() != null && !record.getUpsert().isEmpty()) { + if (record.getUpsertType() != null) { + FlowEnumUpdateType updateType = null; + if (record.getUpsertType() == UpsertType.REPLACE) { + updateType = FlowEnumUpdateType.REPLACE; + } else if (record.getUpsertType() == UpsertType.UPDATE) { + updateType = FlowEnumUpdateType.UPDATE; + } + V1Upsert upsert = V1Upsert.builder().uniqueColumns(record.getUpsert()).updateType(updateType).build(); + data.upsert(upsert); + } else { + V1Upsert upsert = V1Upsert.builder().uniqueColumns(record.getUpsert()).build(); + data.upsert(upsert); + } + } + insertRecordDataList.add(data.build()); + } + + V1InsertRequest.Builder builder = V1InsertRequest.builder() + .vaultId(config.getVaultId()) + .records(insertRecordDataList); + + if (request.getTable() != null && !request.getTable().isEmpty()) { + builder.tableName(request.getTable()); + } + + if (request.getUpsert() != null && !request.getUpsert().isEmpty()) { + if (request.getUpsertType() != null) { + FlowEnumUpdateType updateType = null; + if (request.getUpsertType() == UpsertType.REPLACE) { + updateType = FlowEnumUpdateType.REPLACE; + } else if (request.getUpsertType() == UpsertType.UPDATE) { + updateType = FlowEnumUpdateType.UPDATE; + } + V1Upsert upsert = V1Upsert.builder().uniqueColumns(request.getUpsert()).updateType(updateType).build(); + builder.upsert(upsert); + } else { + V1Upsert upsert = V1Upsert.builder().uniqueColumns(request.getUpsert()).build(); + builder.upsert(upsert); + } + } + return builder.build(); + + } + + public static InsertResponse buildInsertResponse(V1InsertResponse res) { + ArrayList> insertedFields = new ArrayList<>(); + ArrayList> errors = new ArrayList<>(); + + if (res.getRecords().isPresent()) { + for (V1RecordResponseObject record : res.getRecords().get()) { + if (record.getError().isPresent()) { + HashMap errorRecord = new HashMap<>(); + record.getSkyflowId().ifPresent(skyflowId -> errorRecord.put("skyflowId", skyflowId)); + record.getTableName().ifPresent(tableName -> errorRecord.put("tableName", tableName)); + errorRecord.put("error", record.getError().get()); + record.getHttpCode().ifPresent(httpCode -> errorRecord.put("httpCode", httpCode)); + errors.add(errorRecord); + } else { + HashMap insertedRecord = new HashMap<>(); + record.getSkyflowId().ifPresent(skyflowId -> insertedRecord.put("skyflowId", skyflowId)); + record.getTokens().ifPresent(insertedRecord::putAll); + insertedFields.add(insertedRecord); + } + } + } + return new InsertResponse(insertedFields, errors); + } + public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest getDetokenizeRequestBody(DetokenizeRequest request, String vaultid) { + List detokenizeData = request.getDetokenizeData(); + List tokens = new ArrayList<>(); + for(int i = 0; i< detokenizeData.size(); i++){ + tokens.add(detokenizeData.get(i).getToken()); + } + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest.Builder builder = + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest.builder() + .vaultId(vaultid) + .tokens(tokens); + if (request.getTokenGroupRedactions() != null) { + List tokenGroupRedactionsList = new ArrayList<>(); + for (com.skyflow.vault.data.TokenGroupRedactions tokenGroupRedactions : request.getTokenGroupRedactions()) { + com.skyflow.generated.rest.types.V1TokenGroupRedactions redactions = + com.skyflow.generated.rest.types.V1TokenGroupRedactions.builder() + .tokenGroupName(tokenGroupRedactions.getTokenGroupName()) + .redaction(tokenGroupRedactions.getRedaction()) + .build(); + tokenGroupRedactionsList.add(redactions); + } + + builder.tokenGroupRedactions(tokenGroupRedactionsList); + } + return builder.build(); + } + + public static DetokenizeResponse buildDetokenizeResponse(V1FlowDetokenizeResponse res) { + ArrayList detokenizedFields = new ArrayList<>(); + ArrayList errors = new ArrayList<>(); + + if (res.getResponse().isPresent()) { + for (V1FlowDetokenizeResponseObject record : res.getResponse().get()) { + String token = record.getToken().orElse(null); + String tokenGroupName = record.getTokenGroupName().orElse(null); + Map metadata = record.getMetadata().orElse(null); + if (record.getError().isPresent()) { + errors.add(new DetokenizeRecordResponse(token, null, record.getError().get(), tokenGroupName, metadata)); + } else { + Object value = record.getValue().orElse(null); + detokenizedFields.add(new DetokenizeRecordResponse(token, value, null, tokenGroupName, metadata)); + } + } + } + return new DetokenizeResponse(detokenizedFields, errors); + } } diff --git a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java index 06995825..c94fe05b 100644 --- a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java @@ -2,6 +2,7 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; +import com.skyflow.enums.InterfaceName; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; @@ -9,8 +10,10 @@ import com.skyflow.utils.Constants; import com.skyflow.utils.Utils; import com.skyflow.utils.logger.LogUtil; +import com.skyflow.vault.data.*; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -147,4 +150,164 @@ public static void validateVaultConfiguration(VaultConfig vaultConfig) throws Sk } } + + public static void validateInsertRequest(InsertRequest insertRequest) throws SkyflowException { + String table = insertRequest.getTable(); + ArrayList records = insertRequest.getRecords(); + if (records == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.RECORDS_IS_REQUIRED.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.RecordsKeyError.getMessage()); + } else if (records.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_RECORDS.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRecords.getMessage()); + } +// else if (records.size() > 10000) { +// LogUtil.printErrorLog(ErrorLogs.RECORD_SIZE_EXCEED.getLog()); +// throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.RecordSizeExceedError.getMessage()); +// } + for (InsertRecord record : records) { + if(record == null){ + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_RECORD.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidRecord.getMessage()); + } + } + + // table check if specified for both + if (insertRequest.getTable() != null && !table.trim().isEmpty()){ // if table name specified at both place + for (InsertRecord record : records) { + if (record.getTable() != null && !record.getTable().trim().isEmpty()){ + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TABLE_SPECIFIED_AT_BOTH_PLACE.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TableSpecifiedInRequestAndRecordObject.getMessage()); + } + } + } + // table check if not specified for both or if missing in any object + if (insertRequest.getTable() == null || table.trim().isEmpty()){ // if table name specified at both place + for (InsertRecord record : records) { + if (record.getTable() == null || record.getTable().trim().isEmpty()){ + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TABLE_NOT_SPECIFIED_AT_BOTH_PLACE.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TableNotSpecifiedInRequestAndRecordObject.getMessage()); + } + } + } + // upsert check 1 + if (insertRequest.getTable() != null && !table.trim().isEmpty()){ // if table name specified at both place + for (InsertRecord record : records) { + if (record.getUpsert() != null && record.getUpsert().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_UPSERT_VALUES.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyUpsertValues.getMessage()); + } + if (record.getUpsert() != null && !record.getUpsert().isEmpty()){ + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.UPSERT_TABLE_REQUEST_AT_RECORD_LEVEL.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.UpsertTableRequestAtRecordLevel.getMessage()); + } + } + } + // upsert check 2 + if (insertRequest.getTable() == null || table.trim().isEmpty()){ + if (insertRequest.getUpsert() != null && !insertRequest.getUpsert().isEmpty()){ + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.UPSERT_TABLE_REQUEST_AT_REQUEST_LEVEL.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.UpsertTableRequestAtRequestLevel.getMessage()); + } + } + + if (insertRequest.getUpsert() != null && insertRequest.getUpsert().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_UPSERT_VALUES.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyUpsertValues.getMessage()); + } + + for (InsertRecord record : records) { + if (record != null ) { + if (record.getData() != null){ + for (String key : record.getData().keySet()) { + if (key == null || key.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_KEY_IN_VALUES.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyKeyInRecords.getMessage()); + } else { + Object value = record.getData().get(key); + if (value == null || value.toString().trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_VALUE_IN_VALUES.getLog(), + InterfaceName.INSERT.getName(), key + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyValueInValues.getMessage()); + } + } + } + } + } + } + } + + public static void validateDetokenizeRequest(DetokenizeRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.DETOKENIZE_REQUEST_NULL.getLog(), InterfaceName.DETOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.DetokenizeRequestNull.getMessage()); + } + ArrayList tokens = request.getDetokenizeData(); + if (tokens == null || tokens.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_DETOKENIZE_DATA.getLog(), InterfaceName.DETOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDetokenizeData.getMessage()); + } +// if (tokens.size() > 10000) { +// LogUtil.printErrorLog(ErrorLogs.TOKENS_SIZE_EXCEED.getLog()); +// throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TokensSizeExceedError.getMessage()); +// } + for (int index = 0; index < tokens.size(); index++) { + DetokenizeData token = tokens.get(index); + if (token != null && token.getToken().isEmpty() && token.getToken().trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_DETOKENIZE_DATA.getLog(), + InterfaceName.DETOKENIZE.getName(), + String.valueOf(index))); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenInDetokenizeData.getMessage()); + } + } + + List groupRedactions = request.getTokenGroupRedactions(); + if (groupRedactions != null && !groupRedactions.isEmpty()) { + for (TokenGroupRedactions group : groupRedactions) { + if (group == null) { + LogUtil.printErrorLog(Utils.parameterizedString(ErrorLogs.NULL_TOKEN_REDACTION_GROUP_OBJECT.getLog(), InterfaceName.DETOKENIZE.getName())); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullTokenGroupRedactions.getMessage()); + } + String groupName = group.getTokenGroupName(); + String redaction = group.getRedaction(); + if (groupName == null || groupName.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString(ErrorLogs.NULL_TOKEN_GROUP_NAME_IN_TOKEN_GROUP.getLog(), InterfaceName.DETOKENIZE.getName())); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullTokenGroupNameInTokenGroup.getMessage()); + } + if (redaction == null || redaction.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString(ErrorLogs.EMPTY_OR_NULL_REDACTION_IN_TOKEN_GROUP.getLog(), InterfaceName.DETOKENIZE.getName())); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullRedactionInTokenGroup.getMessage()); + } + } + } + } + + } diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java index 6afd5cdb..24ba2b3f 100644 --- a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -7,11 +7,19 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; +import com.skyflow.generated.rest.types.V1InsertResponse; +import com.skyflow.logs.ErrorLogs; +import com.skyflow.logs.InfoLogs; +import com.skyflow.utils.Constants; import com.skyflow.utils.Utils; -import com.skyflow.vault.data.DetokenizeRequest; -import com.skyflow.vault.data.DetokenizeResponse; -import com.skyflow.vault.data.InsertRequest; -import com.skyflow.vault.data.InsertResponse; +import com.skyflow.utils.logger.LogUtil; +import com.skyflow.utils.validations.Validations; +import com.skyflow.vault.data.*; + +import static com.skyflow.utils.Utils.*; public final class VaultController extends VaultClient implements IVaultController { @@ -21,14 +29,57 @@ public final class VaultController extends VaultClient public VaultController(VaultConfig vaultConfig, Credentials credentials) throws SkyflowException { super(vaultConfig, credentials); } + private RequestOptions buildRequestOptions() { + RequestOptions.Builder builder = RequestOptions.builder() + .addHeader(Constants.SDK_METRICS_HEADER_KEY, metrics.toString()); + return builder.build(); + } @Override public InsertResponse insert(InsertRequest request) throws SkyflowException { - return null; + try { + LogUtil.printInfoLog(InfoLogs.INSERT_TRIGGERED.getLog()); + LogUtil.printInfoLog(InfoLogs.VALIDATE_INSERT_REQUEST.getLog()); + Validations.validateInsertRequest(request); + setBearerToken(); + V1InsertRequest insertRequest = getBulkInsertRequestBody(request, super.getVaultConfig()); + V1InsertResponse response = this.getRecordsApi().withRawResponse().insert(insertRequest, buildRequestOptions()).body(); + return buildInsertResponse(response); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } } @Override public DetokenizeResponse detokenize(DetokenizeRequest request) throws SkyflowException { + try { + LogUtil.printInfoLog(InfoLogs.DETOKENIZE_TRIGGERED.getLog()); + LogUtil.printInfoLog(InfoLogs.VALIDATE_DETOKENIZE_REQUEST.getLog()); + Validations.validateDetokenizeRequest(request); + setBearerToken(); + + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest requestDetokenize = getDetokenizeRequestBody(request, this.getVaultConfig().getVaultId()); + com.skyflow.generated.rest.types.V1FlowDetokenizeResponse response = this.getRecordsApi().withRawResponse().detokenize(requestDetokenize, buildRequestOptions()).body(); + + return buildDetokenizeResponse(response); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } + } + + public TokenizeResponse tokenize(TokenizeRequest request){ + LogUtil.printInfoLog(InfoLogs.TOKENIZE_TRIGGERED.getLog()); + try { + + } catch (Exception e) { + throw new RuntimeException(e); + } return null; } + + } \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeData.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeData.java new file mode 100644 index 00000000..dcd8a2c8 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeData.java @@ -0,0 +1,8 @@ +package com.skyflow.vault.data; + + +public class DetokenizeData extends BaseDetokenizeData { + public DetokenizeData(String token) { + super(token); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRecordResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRecordResponse.java new file mode 100644 index 00000000..27063e8e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRecordResponse.java @@ -0,0 +1,37 @@ +package com.skyflow.vault.data; + + +import com.google.gson.Gson; + +import java.util.Map; + +public class DetokenizeRecordResponse extends BaseDetokenizeRecordResponse { + private String tokenGroupName; + private Map metadata; + private Object value; + + public DetokenizeRecordResponse(String token, Object value, String error, String tokenGroupName, Map metadata) { + super(token, error); + this.value = value; + this.tokenGroupName = tokenGroupName; + this.metadata = metadata; + + } + + public String getTokenGroupName() { + return tokenGroupName; + } + public Map getMetadata() { + return metadata; + } + + public Object getValue(){ + return this.value; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java index 0cd8b159..67be6140 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeRequest.java @@ -1,4 +1,41 @@ package com.skyflow.vault.data; +import java.util.ArrayList; +import java.util.List; + public class DetokenizeRequest extends BaseDetokenizeRequest{ + private final DetokenizeRequestBuilder builder; + + private DetokenizeRequest(DetokenizeRequestBuilder builder) { + this.builder = builder; + } + + public static DetokenizeRequestBuilder builder() { + return new DetokenizeRequestBuilder(); + } + + public ArrayList getDetokenizeData() { + return this.builder.detokenizeData; + } + public List getTokenGroupRedactions(){ + return this.builder.tokenGroupRedactions; + } + + public static final class DetokenizeRequestBuilder { + private ArrayList detokenizeData; + private List tokenGroupRedactions; + + public DetokenizeRequestBuilder detokenizeData(ArrayList detokenizeData) { + this.detokenizeData = detokenizeData; + return this; + } + public DetokenizeRequestBuilder tokenGroupRedactions(List tokenGroupRedactions){ + this.tokenGroupRedactions = tokenGroupRedactions; + return this; + } + public DetokenizeRequest build() { + return new DetokenizeRequest(this); + } + } + } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java index 91dbe710..226b8444 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponse.java @@ -1,4 +1,29 @@ package com.skyflow.vault.data; -public class DetokenizeResponse extends BaseDetokenizeResponse{ -} +import com.google.gson.Gson; + +import java.util.ArrayList; + +public class DetokenizeResponse { + private final ArrayList detokenizedFields; + private final ArrayList errors; + + public DetokenizeResponse(ArrayList detokenizedFields, ArrayList errors) { + this.detokenizedFields = detokenizedFields; + this.errors = errors; + } + + public ArrayList getDetokenizedFields() { + return detokenizedFields; + } + + public ArrayList getErrors() { + return errors; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java index 4d8e8cae..b4ef6b17 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java +++ b/flowvault/src/main/java/com/skyflow/vault/data/InsertRequest.java @@ -12,7 +12,6 @@ private InsertRequest(InsertRequestBuilder builder) { this.builder = builder; } - public static InsertRequestBuilder builder() { return new InsertRequestBuilder(); } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java index 2d7e6e32..5a969d8d 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java +++ b/flowvault/src/main/java/com/skyflow/vault/data/InsertResponse.java @@ -1,4 +1,10 @@ package com.skyflow.vault.data; +import java.util.ArrayList; +import java.util.HashMap; + public class InsertResponse extends BaseInsertResponse{ + public InsertResponse(ArrayList> insertedFields, ArrayList> errors) { + super(insertedFields, errors); + } } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenGroupRedactions.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenGroupRedactions.java new file mode 100644 index 00000000..3f89014c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenGroupRedactions.java @@ -0,0 +1,39 @@ +package com.skyflow.vault.data; + +public class TokenGroupRedactions { + private final TokenGroupRedactionsBuilder builder; + + private TokenGroupRedactions(TokenGroupRedactionsBuilder builder) { + this.builder = builder; + } + public String getTokenGroupName() { + return this.builder.tokenGroupName; + } + + public String getRedaction() { + return this.builder.redaction; + } + + public static TokenGroupRedactionsBuilder builder() { + return new TokenGroupRedactionsBuilder(); + } + + public static final class TokenGroupRedactionsBuilder { + private String tokenGroupName; + private String redaction; + + public TokenGroupRedactionsBuilder tokenGroupName(String tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + public TokenGroupRedactionsBuilder redaction(String redaction) { + this.redaction = redaction; + return this; + } + + public TokenGroupRedactions build() { + return new TokenGroupRedactions(this); + } + } +} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java new file mode 100644 index 00000000..f6b6cf99 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class TokenizeRequest { +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java new file mode 100644 index 00000000..403ad53c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java @@ -0,0 +1,4 @@ +package com.skyflow.vault.data; + +public class TokenizeResponse { +} diff --git a/pom.xml b/pom.xml index 1066c387..0b805a52 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,22 @@ org.apache.maven.plugins maven-surefire-plugin - 2.22.2 + 3.2.5 + + false + + @{argLine} + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.net=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.io=ALL-UNNAMED + --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED + + + **/*Test.java + **/*Tests.java + + org.jacoco diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index 396291bd..b8a056de 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -91,38 +91,6 @@ protected void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowExcept Validations.validateVaultConfig(vaultConfig); } - @Override - protected VaultConfig cloneVaultConfig(VaultConfig vaultConfig) { - try { - return (VaultConfig) vaultConfig.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - @Override - protected String extractVaultId(VaultConfig vaultConfig) { - return vaultConfig.getVaultId(); - } - - @Override - protected VaultConfig mergeVaultConfig(VaultConfig incoming, VaultConfig existing) { - if (incoming.getEnv() != null) { - existing.setEnv(incoming.getEnv()); - } - if (incoming.getClusterId() != null) { - existing.setClusterId(incoming.getClusterId()); - } - if (incoming.getCredentials() != null) { - try { - existing.setCredentials((Credentials) incoming.getCredentials().clone()); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - return existing; - } - @Override protected void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowException { this.vaultClientsMap.put(vaultConfig.getVaultId(), new VaultController(vaultConfig, this.skyflowCredentials)); diff --git a/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java b/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java index eb4c2020..cd305df1 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java @@ -3,11 +3,9 @@ */ package com.skyflow.generated.rest; -import com.skyflow.generated.rest.ApiClientBuilder; import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.Suppliers; import com.skyflow.generated.rest.resources.audit.AuditClient; -import com.skyflow.generated.rest.resources.authentication.AuthenticationClient; import com.skyflow.generated.rest.resources.binlookup.BinLookupClient; import com.skyflow.generated.rest.resources.files.FilesClient; import com.skyflow.generated.rest.resources.guardrails.GuardrailsClient; @@ -15,7 +13,6 @@ import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.generated.rest.resources.strings.StringsClient; import com.skyflow.generated.rest.resources.tokens.TokensClient; - import java.util.function.Supplier; public class ApiClient { @@ -31,8 +28,6 @@ public class ApiClient { protected final Supplier queryClient; - protected final Supplier authenticationClient; - protected final Supplier filesClient; protected final Supplier stringsClient; @@ -46,7 +41,6 @@ public ApiClient(ClientOptions clientOptions) { this.recordsClient = Suppliers.memoize(() -> new RecordsClient(clientOptions)); this.tokensClient = Suppliers.memoize(() -> new TokensClient(clientOptions)); this.queryClient = Suppliers.memoize(() -> new QueryClient(clientOptions)); - this.authenticationClient = Suppliers.memoize(() -> new AuthenticationClient(clientOptions)); this.filesClient = Suppliers.memoize(() -> new FilesClient(clientOptions)); this.stringsClient = Suppliers.memoize(() -> new StringsClient(clientOptions)); this.guardrailsClient = Suppliers.memoize(() -> new GuardrailsClient(clientOptions)); @@ -72,10 +66,6 @@ public QueryClient query() { return this.queryClient.get(); } - public AuthenticationClient authentication() { - return this.authenticationClient.get(); - } - public FilesClient files() { return this.filesClient.get(); } diff --git a/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java b/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java index ec3543a3..f0ca2c05 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java @@ -3,11 +3,9 @@ */ package com.skyflow.generated.rest; -import com.skyflow.generated.rest.AsyncApiClientBuilder; import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.Suppliers; import com.skyflow.generated.rest.resources.audit.AsyncAuditClient; -import com.skyflow.generated.rest.resources.authentication.AsyncAuthenticationClient; import com.skyflow.generated.rest.resources.binlookup.AsyncBinLookupClient; import com.skyflow.generated.rest.resources.files.AsyncFilesClient; import com.skyflow.generated.rest.resources.guardrails.AsyncGuardrailsClient; @@ -15,7 +13,6 @@ import com.skyflow.generated.rest.resources.records.AsyncRecordsClient; import com.skyflow.generated.rest.resources.strings.AsyncStringsClient; import com.skyflow.generated.rest.resources.tokens.AsyncTokensClient; - import java.util.function.Supplier; public class AsyncApiClient { @@ -31,8 +28,6 @@ public class AsyncApiClient { protected final Supplier queryClient; - protected final Supplier authenticationClient; - protected final Supplier filesClient; protected final Supplier stringsClient; @@ -46,7 +41,6 @@ public AsyncApiClient(ClientOptions clientOptions) { this.recordsClient = Suppliers.memoize(() -> new AsyncRecordsClient(clientOptions)); this.tokensClient = Suppliers.memoize(() -> new AsyncTokensClient(clientOptions)); this.queryClient = Suppliers.memoize(() -> new AsyncQueryClient(clientOptions)); - this.authenticationClient = Suppliers.memoize(() -> new AsyncAuthenticationClient(clientOptions)); this.filesClient = Suppliers.memoize(() -> new AsyncFilesClient(clientOptions)); this.stringsClient = Suppliers.memoize(() -> new AsyncStringsClient(clientOptions)); this.guardrailsClient = Suppliers.memoize(() -> new AsyncGuardrailsClient(clientOptions)); @@ -72,10 +66,6 @@ public AsyncQueryClient query() { return this.queryClient.get(); } - public AsyncAuthenticationClient authentication() { - return this.authenticationClient.get(); - } - public AsyncFilesClient files() { return this.filesClient.get(); } diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java b/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java index da41fb25..2a5f0710 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java @@ -35,7 +35,7 @@ private ClientOptions( { put("X-Fern-Language", "JAVA"); put("X-Fern-SDK-Name", "com.skyflow.fern:api-sdk"); - put("X-Fern-SDK-Version", "0.0.385"); + put("X-Fern-SDK-Version", "0.0.98"); } }); this.headerSuppliers = headerSuppliers; diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java b/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java index c27d39a0..6b459431 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java @@ -3,14 +3,12 @@ */ package com.skyflow.generated.rest.core; -import com.skyflow.generated.rest.core.InputStreamRequestBody; +import java.io.InputStream; +import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; import org.jetbrains.annotations.Nullable; -import java.io.InputStream; -import java.util.Objects; - /** * Represents a file stream with associated metadata for file uploads. */ diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java b/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java index 55c3c971..545f6088 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java @@ -3,6 +3,9 @@ */ package com.skyflow.generated.rest.core; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.internal.Util; @@ -11,10 +14,6 @@ import okio.Source; import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; - /** * A custom implementation of OkHttp's RequestBody that wraps an InputStream. * This class allows streaming of data from an InputStream directly to an HTTP request body, diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java b/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java index 3f3a2213..3b7894e0 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java @@ -10,8 +10,6 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.skyflow.generated.rest.core.DateTimeDeserializer; - import java.io.IOException; public final class ObjectMappers { diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java b/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java index c0687736..e9e18fb9 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java @@ -7,11 +7,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import okhttp3.HttpUrl; import okhttp3.MultipartBody; -import java.util.*; - public class QueryStringMapper { private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER; diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java index 1bb0b5dc..d8df7715 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java @@ -3,10 +3,9 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Response; - import java.io.FilterInputStream; import java.io.IOException; +import okhttp3.Response; /** * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java index e6c1a525..ed894407 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java @@ -3,10 +3,9 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Response; - import java.io.FilterReader; import java.io.IOException; +import okhttp3.Response; /** * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java b/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java index 7a28c3c9..eda7d265 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java @@ -3,13 +3,12 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Interceptor; -import okhttp3.Response; - import java.io.IOException; import java.time.Duration; import java.util.Optional; import java.util.Random; +import okhttp3.Interceptor; +import okhttp3.Response; public class RetryInterceptor implements Interceptor { diff --git a/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java index 80ae5e7c..02c36c4b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java +++ b/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java @@ -4,20 +4,21 @@ package com.skyflow.generated.rest.errors; import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; import okhttp3.Response; public final class BadRequestError extends ApiClientApiException { /** * The body of the response that triggered the exception. */ - private final Object body; + private final ErrorResponse body; - public BadRequestError(Object body) { + public BadRequestError(ErrorResponse body) { super("BadRequestError", 400, body); this.body = body; } - public BadRequestError(Object body, Response rawResponse) { + public BadRequestError(ErrorResponse body, Response rawResponse) { super("BadRequestError", 400, body, rawResponse); this.body = body; } @@ -26,7 +27,7 @@ public BadRequestError(Object body, Response rawResponse) { * @return the body */ @Override - public Object body() { + public ErrorResponse body() { return this.body; } } diff --git a/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java index 3bc254bc..00ddc4ce 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java +++ b/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java @@ -4,20 +4,21 @@ package com.skyflow.generated.rest.errors; import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; import okhttp3.Response; public final class UnauthorizedError extends ApiClientApiException { /** * The body of the response that triggered the exception. */ - private final Object body; + private final ErrorResponse body; - public UnauthorizedError(Object body) { + public UnauthorizedError(ErrorResponse body) { super("UnauthorizedError", 401, body); this.body = body; } - public UnauthorizedError(Object body, Response rawResponse) { + public UnauthorizedError(ErrorResponse body, Response rawResponse) { super("UnauthorizedError", 401, body, rawResponse); this.body = body; } @@ -26,7 +27,7 @@ public UnauthorizedError(Object body, Response rawResponse) { * @return the body */ @Override - public Object body() { + public ErrorResponse body() { return this.body; } } diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java index e1516eaf..875ca259 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java @@ -4,15 +4,27 @@ package com.skyflow.generated.rest.resources.audit; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.QueryStringMapper; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.audit.requests.AuditServiceListAuditEventsRequest; import com.skyflow.generated.rest.types.V1AuditResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawAuditClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java index 68cd5e3b..bfec3bf2 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java @@ -4,13 +4,23 @@ package com.skyflow.generated.rest.resources.audit; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.QueryStringMapper; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.audit.requests.AuditServiceListAuditEventsRequest; import com.skyflow.generated.rest.types.V1AuditResponse; -import okhttp3.*; - import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawAuditClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java index e9f8cf12..8b6686e4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java @@ -3,16 +3,26 @@ */ package com.skyflow.generated.rest.resources.audit.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.resources.audit.types.*; -import org.jetbrains.annotations.NotNull; - +import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsActionType; +import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextAccessType; +import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextActorType; +import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextAuthMode; +import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsResourceType; +import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestSortOpsOrderBy; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = AuditServiceListAuditEventsRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java index 9cf03c7d..2a3f5f4f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java @@ -4,15 +4,28 @@ package com.skyflow.generated.rest.resources.binlookup; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.binlookup.requests.V1BinListRequest; import com.skyflow.generated.rest.types.V1BinListResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawBinLookupClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java index 21e77017..bb08039b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java @@ -4,13 +4,24 @@ package com.skyflow.generated.rest.resources.binlookup; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.binlookup.requests.V1BinListRequest; import com.skyflow.generated.rest.types.V1BinListResponse; -import okhttp3.*; - import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawBinLookupClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java index def40293..af827e01 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java @@ -3,12 +3,21 @@ */ package com.skyflow.generated.rest.resources.binlookup.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1VaultSchemaConfig; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BinListRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java index 01031423..1f157223 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java @@ -5,11 +5,20 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.files.requests.*; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; +import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; +import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; - import java.util.concurrent.CompletableFuture; public class AsyncFilesClient { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java index e7f008e8..f497bb02 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java @@ -4,20 +4,44 @@ package com.skyflow.generated.rest.resources.files; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.QueryStringMapper; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.files.requests.*; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; +import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; +import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawFilesClient { protected final ClientOptions clientOptions; @@ -78,12 +102,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -166,12 +190,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -254,12 +278,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -342,12 +366,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -430,12 +454,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -518,12 +542,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -606,12 +630,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -694,12 +718,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -782,12 +806,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -870,12 +894,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -959,12 +983,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java index bcda96e6..8d083d76 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java @@ -5,7 +5,17 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.files.requests.*; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; +import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; +import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java index d277d224..0d44668e 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java @@ -4,18 +4,40 @@ package com.skyflow.generated.rest.resources.files; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.QueryStringMapper; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.files.requests.*; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; +import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; +import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; +import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; -import okhttp3.*; - import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawFilesClient { protected final ClientOptions clientOptions; @@ -70,10 +92,10 @@ public ApiClientHttpResponse deidentifyFile( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -138,10 +160,10 @@ public ApiClientHttpResponse deidentifyAudio( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -206,10 +228,10 @@ public ApiClientHttpResponse deidentifyDocument( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -274,10 +296,10 @@ public ApiClientHttpResponse deidentifyPdf( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -342,10 +364,10 @@ public ApiClientHttpResponse deidentifyImage( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -410,10 +432,10 @@ public ApiClientHttpResponse deidentifyPresentation( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -478,10 +500,10 @@ public ApiClientHttpResponse deidentifySpreadsheet( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -546,10 +568,10 @@ public ApiClientHttpResponse deidentifyStructuredText( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -613,10 +635,10 @@ public ApiClientHttpResponse deidentifyText( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -680,10 +702,10 @@ public ApiClientHttpResponse reidentifyFile( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -749,10 +771,10 @@ public ApiClientHttpResponse getRun( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java index c2baa931..d1cadca3 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java @@ -3,7 +3,13 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem; @@ -11,10 +17,13 @@ import com.skyflow.generated.rest.types.FileDataDeidentifyAudio; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileAudioRequestDeidentifyAudio.Builder.class) public final class DeidentifyFileAudioRequestDeidentifyAudio { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java index 1844a116..5b6a653f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java @@ -3,17 +3,26 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyPdf; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileDocumentPdfRequestDeidentifyPdf.Builder.class) public final class DeidentifyFileDocumentPdfRequestDeidentifyPdf { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java index 25ddea9c..015bba9e 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java @@ -3,7 +3,13 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileImageRequestDeidentifyImageEntityTypesItem; @@ -11,10 +17,13 @@ import com.skyflow.generated.rest.types.FileDataDeidentifyImage; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileImageRequestDeidentifyImage.Builder.class) public final class DeidentifyFileImageRequestDeidentifyImage { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java index 62d77229..c2cdcfb5 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java @@ -3,17 +3,26 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestEntityTypesItem; import com.skyflow.generated.rest.types.FileData; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequest.Builder.class) public final class DeidentifyFileRequest { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java index c4d9841d..fc3db52a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java @@ -3,17 +3,26 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyDocumentEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyDocument; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyDocument.Builder.class) public final class DeidentifyFileRequestDeidentifyDocument { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java index e1cea77f..f45802ec 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java @@ -3,17 +3,26 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyPresentationEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyPresentation; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyPresentation.Builder.class) public final class DeidentifyFileRequestDeidentifyPresentation { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java index 10ca8feb..93ea921a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java @@ -3,17 +3,26 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifySpreadsheet; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifySpreadsheet.Builder.class) public final class DeidentifyFileRequestDeidentifySpreadsheet { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java index e3f555b8..b579fe1b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java @@ -3,17 +3,26 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyStructuredText; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyStructuredText.Builder.class) public final class DeidentifyFileRequestDeidentifyStructuredText { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java index 8457c790..7a7c6615 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java @@ -3,17 +3,26 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyTextEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyText; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyText.Builder.class) public final class DeidentifyFileRequestDeidentifyText { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java index cde24227..490392f1 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java index 5cd22747..0f5e79ab 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java @@ -3,17 +3,22 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.FileDataReidentifyFile; import com.skyflow.generated.rest.types.Format; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ReidentifyFileRequestReidentifyFile.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java index 80853472..28829a68 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java @@ -4,18 +4,31 @@ package com.skyflow.generated.rest.resources.guardrails; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; import com.skyflow.generated.rest.resources.guardrails.requests.DetectGuardrailsRequest; import com.skyflow.generated.rest.types.DetectGuardrailsResponse; import com.skyflow.generated.rest.types.ErrorResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawGuardrailsClient { protected final ClientOptions clientOptions; @@ -76,12 +89,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java index 5bf5c31a..bdf632ca 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java @@ -4,16 +4,27 @@ package com.skyflow.generated.rest.resources.guardrails; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; import com.skyflow.generated.rest.resources.guardrails.requests.DetectGuardrailsRequest; import com.skyflow.generated.rest.types.DetectGuardrailsResponse; import com.skyflow.generated.rest.types.ErrorResponse; -import okhttp3.*; - import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawGuardrailsClient { protected final ClientOptions clientOptions; @@ -68,10 +79,10 @@ public ApiClientHttpResponse checkGuardrails( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java index 75250f8c..9063fed8 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java @@ -3,13 +3,22 @@ */ package com.skyflow.generated.rest.resources.guardrails.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectGuardrailsRequest.Builder.class) public final class DetectGuardrailsRequest { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java index 7b8c9383..96e2dc0b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java @@ -4,15 +4,28 @@ package com.skyflow.generated.rest.resources.query; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.types.V1GetQueryResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawQueryClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java index ec88ae93..3e5bee51 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java @@ -4,13 +4,24 @@ package com.skyflow.generated.rest.resources.query; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.types.V1GetQueryResponse; -import okhttp3.*; - import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawQueryClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java index 000cd685..60565eb5 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.resources.query.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java index b1c9ae18..8840b51c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java @@ -4,21 +4,54 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.QueryStringMapper; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.records.requests.*; -import com.skyflow.generated.rest.types.*; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - +import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; +import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.UploadFileV2Response; +import com.skyflow.generated.rest.types.V1BatchOperationResponse; +import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; +import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; +import com.skyflow.generated.rest.types.V1DeleteFileResponse; +import com.skyflow.generated.rest.types.V1DeleteRecordResponse; +import com.skyflow.generated.rest.types.V1FieldRecords; +import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; +import com.skyflow.generated.rest.types.V1InsertRecordResponse; +import com.skyflow.generated.rest.types.V1UpdateRecordResponse; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawRecordsClient { protected final ClientOptions clientOptions; @@ -989,12 +1022,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 404: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java index ed7240c9..c6925b50 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java @@ -5,9 +5,24 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.requests.*; -import com.skyflow.generated.rest.types.*; - +import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; +import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; +import com.skyflow.generated.rest.types.UploadFileV2Response; +import com.skyflow.generated.rest.types.V1BatchOperationResponse; +import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; +import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; +import com.skyflow.generated.rest.types.V1DeleteFileResponse; +import com.skyflow.generated.rest.types.V1DeleteRecordResponse; +import com.skyflow.generated.rest.types.V1FieldRecords; +import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; +import com.skyflow.generated.rest.types.V1InsertRecordResponse; +import com.skyflow.generated.rest.types.V1UpdateRecordResponse; import java.io.File; import java.util.Optional; import java.util.concurrent.CompletableFuture; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java index 29530b56..977e84bb 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java @@ -4,19 +4,50 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.QueryStringMapper; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.records.requests.*; -import com.skyflow.generated.rest.types.*; -import okhttp3.*; - +import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; +import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.UploadFileV2Response; +import com.skyflow.generated.rest.types.V1BatchOperationResponse; +import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; +import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; +import com.skyflow.generated.rest.types.V1DeleteFileResponse; +import com.skyflow.generated.rest.types.V1DeleteRecordResponse; +import com.skyflow.generated.rest.types.V1FieldRecords; +import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; +import com.skyflow.generated.rest.types.V1InsertRecordResponse; +import com.skyflow.generated.rest.types.V1UpdateRecordResponse; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Optional; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawRecordsClient { protected final ClientOptions clientOptions; @@ -831,10 +862,10 @@ public ApiClientHttpResponse uploadFileV2( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 404: throw new NotFoundError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java index 7cf3e02b..7b4599c6 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java @@ -5,10 +5,24 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.RawRecordsClient; -import com.skyflow.generated.rest.resources.records.requests.*; -import com.skyflow.generated.rest.types.*; - +import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; +import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; +import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; +import com.skyflow.generated.rest.types.UploadFileV2Response; +import com.skyflow.generated.rest.types.V1BatchOperationResponse; +import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; +import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; +import com.skyflow.generated.rest.types.V1DeleteFileResponse; +import com.skyflow.generated.rest.types.V1DeleteRecordResponse; +import com.skyflow.generated.rest.types.V1FieldRecords; +import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; +import com.skyflow.generated.rest.types.V1InsertRecordResponse; +import com.skyflow.generated.rest.types.V1UpdateRecordResponse; import java.io.File; import java.util.Optional; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java index 3efb0a98..fe805970 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java index c1997213..48586839 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java @@ -3,13 +3,22 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1BatchRecord; import com.skyflow.generated.rest.types.V1Byot; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBatchOperationBody.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java index 4b9dcced..b417adbb 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBulkDeleteRecordBody.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java index 9b59168a..22c9090c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java @@ -3,13 +3,23 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.records.types.RecordServiceBulkGetRecordRequestOrderBy; import com.skyflow.generated.rest.resources.records.types.RecordServiceBulkGetRecordRequestRedaction; - -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBulkGetRecordRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java index 91317d02..eef17665 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java @@ -3,12 +3,22 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.records.types.RecordServiceGetRecordRequestRedaction; - -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceGetRecordRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java index e832e396..e1de00f7 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java @@ -3,13 +3,22 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1Byot; import com.skyflow.generated.rest.types.V1FieldRecords; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceInsertRecordBody.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java index f5c7a229..e52af2e4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java @@ -3,12 +3,17 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1Byot; import com.skyflow.generated.rest.types.V1FieldRecords; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java index 81a9f837..f162530c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java @@ -3,15 +3,20 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = UploadFileV2Request.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java index 36b364b5..aed19530 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java @@ -4,7 +4,13 @@ package com.skyflow.generated.rest.resources.strings; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; @@ -13,11 +19,18 @@ import com.skyflow.generated.rest.types.DeidentifyStringResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.IdentifyResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawStringsClient { protected final ClientOptions clientOptions; @@ -78,12 +91,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: @@ -172,12 +185,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response)); return; case 500: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java index da6bec56..560e1931 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java @@ -4,7 +4,13 @@ package com.skyflow.generated.rest.resources.strings; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; @@ -13,9 +19,14 @@ import com.skyflow.generated.rest.types.DeidentifyStringResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.IdentifyResponse; -import okhttp3.*; - import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawStringsClient { protected final ClientOptions clientOptions; @@ -70,10 +81,10 @@ public ApiClientHttpResponse deidentifyString( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -143,10 +154,10 @@ public ApiClientHttpResponse reidentifyString( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java index 06ec6cec..943ddde4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java @@ -3,16 +3,25 @@ */ package com.skyflow.generated.rest.resources.strings.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.strings.types.DeidentifyStringRequestEntityTypesItem; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyStringRequest.Builder.class) public final class DeidentifyStringRequest { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java index 3c42390c..59c1aaf2 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java @@ -3,11 +3,16 @@ */ package com.skyflow.generated.rest.resources.strings.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.Format; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java index 794035bd..fbf69580 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java @@ -4,17 +4,30 @@ package com.skyflow.generated.rest.resources.tokens; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawTokensClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java index 621701af..26d5ea05 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java @@ -9,7 +9,6 @@ import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; - import java.util.concurrent.CompletableFuture; public class AsyncTokensClient { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java index 7ad69d11..5ed17d28 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java @@ -4,15 +4,26 @@ package com.skyflow.generated.rest.resources.tokens; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; -import okhttp3.*; - import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawTokensClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java index 52571f64..59318aa8 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java @@ -3,12 +3,21 @@ */ package com.skyflow.generated.rest.resources.tokens.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1DetokenizeRecordRequest; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1DetokenizePayload.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java index e5fc08f4..9729023e 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java @@ -3,12 +3,21 @@ */ package com.skyflow.generated.rest.resources.tokens.requests; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1TokenizeRecordRequest; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1TokenizePayload.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java index 73aed9c1..210f96c0 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java index bab4b42a..e2028fba 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java index 9d3bbaed..1352c42f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java index dc244be8..a7dd7c68 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java index d5a2ebd5..d2b8e5b6 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java index 1389fa0f..e831f142 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyStringResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java index 9cb2d319..9773dcc3 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java @@ -3,15 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectGuardrailsResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java index b73f7845..c97f7635 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectRunsResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java index 4113b998..565714eb 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ErrorResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java index 4774fa57..bcc23f03 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java @@ -3,13 +3,22 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.jetbrains.annotations.NotNull; -import java.util.*; - @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ErrorResponseError.Builder.class) public final class ErrorResponseError { diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java index fd6fa822..7f58332e 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileData.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java index b6a5ea11..2aa88f7b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyAudio.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java index 5fb12fba..e6390e28 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyDocument.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java index bc5e2c6b..127c5f4c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyImage.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java index 5606e917..20b0314f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyPdf.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java index 0bedabc5..e808f0b2 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyPresentation.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java index dd017bb8..33478d20 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifySpreadsheet.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java index 814d51c3..dad188ce 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyStructuredText.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java index e5c88180..79045d7a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyText.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java index 9148703c..edea3145 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataReidentifyFile.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/Format.java b/v2/src/main/java/com/skyflow/generated/rest/types/Format.java index 1563b90a..68ac94ca 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/Format.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Format.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = Format.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java b/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java index 55be5699..807aee4e 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = GooglerpcStatus.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java index c1bd23c6..e7ae30fc 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java @@ -3,14 +3,18 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = IdentifyResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java b/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java index 4b95c485..9864541a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java b/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java index 40e73b99..9f019b66 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java index a12660cb..b5a4f6f5 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java index b7bc22ca..024200d1 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java b/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java index 37ef8cdf..2fc4b11a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ShiftDates.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java b/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java index 78df8838..81c1e58d 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java index b703895d..f8c1edb4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = TokenTypeMapping.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java b/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java index c9165409..12a5afc7 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java b/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java index 8f5fea5a..c1ddbd58 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java index 037b80bf..d942fdcd 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java index f7ca73f0..c582d06d 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java index 36d7ccce..dd23d77c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java index a54eec6c..ca2bfdc2 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponseEvent.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java index 90d9c538..046c8fb4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponseEventRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java index 8f5fb775..a557da82 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BatchOperationResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java index 3f0455cc..afc572cf 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java index 88c1c125..58472a8b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BinListResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java index b7151598..ddb0d213 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BulkDeleteRecordResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java index 27878fab..c2d3790a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BulkGetRecordResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java index ba4f7349..f2a9db90 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java index 4d9b24eb..4ec85903 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java index 5351d897..2f3bde14 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java index b6fb9cb6..3cf5b59c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java index dd3a9c1f..ba0abbfa 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java index 53660cbe..74f4f6e6 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1DetokenizeResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java index b64b8792..dfbccb8b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java deleted file mode 100644 index 43a86ae0..00000000 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1GetAuthTokenResponse.Builder.class) -public final class V1GetAuthTokenResponse { - private final Optional accessToken; - - private final Optional tokenType; - - private final Map additionalProperties; - - private V1GetAuthTokenResponse( - Optional accessToken, Optional tokenType, Map additionalProperties) { - this.accessToken = accessToken; - this.tokenType = tokenType; - this.additionalProperties = additionalProperties; - } - - /** - * @return AccessToken. - */ - @JsonProperty("accessToken") - public Optional getAccessToken() { - return accessToken; - } - - /** - * @return TokenType : Bearer. - */ - @JsonProperty("tokenType") - public Optional getTokenType() { - return tokenType; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1GetAuthTokenResponse && equalTo((V1GetAuthTokenResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1GetAuthTokenResponse other) { - return accessToken.equals(other.accessToken) && tokenType.equals(other.tokenType); - } - - @Override - public int hashCode() { - return Objects.hash(this.accessToken, this.tokenType); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional accessToken = Optional.empty(); - - private Optional tokenType = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1GetAuthTokenResponse other) { - accessToken(other.getAccessToken()); - tokenType(other.getTokenType()); - return this; - } - - /** - *

AccessToken.

- */ - @JsonSetter(value = "accessToken", nulls = Nulls.SKIP) - public Builder accessToken(Optional accessToken) { - this.accessToken = accessToken; - return this; - } - - public Builder accessToken(String accessToken) { - this.accessToken = Optional.ofNullable(accessToken); - return this; - } - - /** - *

TokenType : Bearer.

- */ - @JsonSetter(value = "tokenType", nulls = Nulls.SKIP) - public Builder tokenType(Optional tokenType) { - this.tokenType = tokenType; - return this; - } - - public Builder tokenType(String tokenType) { - this.tokenType = Optional.ofNullable(tokenType); - return this; - } - - public V1GetAuthTokenResponse build() { - return new V1GetAuthTokenResponse(accessToken, tokenType, additionalProperties); - } - } -} diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java index 3138c766..4bd67013 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java index a44b0f62..821d1f06 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1GetQueryResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java index f8a00001..0addf786 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1InsertRecordResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java index 17f77df6..f69719cf 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java index 43fe264a..2c15ceac 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java index 66721fa1..201a4f60 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java index 05e64bc0..62d77bed 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java @@ -3,11 +3,20 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1TokenizeResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java index d2fcbf1b..03ed7b58 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java index 6fc09854..c19d1cb5 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java index 1542ab0f..cd838305 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java b/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java index 314b5942..594b6d11 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java @@ -3,10 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/logs/ErrorLogs.java b/v2/src/main/java/com/skyflow/logs/ErrorLogs.java deleted file mode 100644 index 47866efc..00000000 --- a/v2/src/main/java/com/skyflow/logs/ErrorLogs.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.skyflow.logs; - -public enum ErrorLogs { - // Client initialization - VAULT_CONFIG_EXISTS("Vault config with vault ID %s1 already exists."), - VAULT_CONFIG_DOES_NOT_EXIST("Vault config with vault ID %s1 doesn't exist."), - VAULT_ID_IS_REQUIRED("Invalid vault config. Vault ID is required."), - EMPTY_VAULT_ID("Invalid vault config. Vault ID can not be empty."), - CLUSTER_ID_IS_REQUIRED("Invalid vault config. Cluster ID is required."), - EMPTY_CLUSTER_ID("Invalid vault config. Cluster ID can not be empty."), - CONNECTION_CONFIG_EXISTS("Connection config with connection ID %s1 already exists."), - CONNECTION_CONFIG_DOES_NOT_EXIST("Connection config with connection ID %s1 doesn't exist."), - CONNECTION_ID_IS_REQUIRED("Invalid connection config. Connection ID is required."), - EMPTY_CONNECTION_ID("Invalid connection config. Connection ID can not be empty."), - CONNECTION_URL_IS_REQUIRED("Invalid connection config. Connection URL is required."), - EMPTY_CONNECTION_URL("Invalid connection config. Connection URL can not be empty."), - INVALID_CONNECTION_URL("Invalid connection config. Connection URL is not a valid URL."), - MULTIPLE_TOKEN_GENERATION_MEANS_PASSED("Invalid credentials. Only one of 'path', 'credentialsString', 'token' or 'apiKey' is allowed."), - NO_TOKEN_GENERATION_MEANS_PASSED("Invalid credentials. Any one of 'path', 'credentialsString', 'token' or 'apiKey' is required."), - EMPTY_CREDENTIALS_PATH("Invalid credentials. Credentials path can not be empty."), - EMPTY_CREDENTIALS_STRING("Invalid credentials. Credentials string can not be empty."), - EMPTY_TOKEN_VALUE("Invalid credentials. Token can not be empty."), - EMPTY_API_KEY_VALUE("Invalid credentials. Api key can not be empty."), - INVALID_API_KEY("Invalid credentials. Api key is invalid."), - EMPTY_ROLES("Invalid credentials. Roles can not be empty."), - EMPTY_OR_NULL_ROLE_IN_ROLES("Invalid credentials. Role can not be null or empty in roles at index %s1."), - EMPTY_OR_NULL_CONTEXT("Invalid credentials. Context can not be empty."), - INVALID_CONTEXT_TYPE("Invalid credentials. Context must be a String or Map."), - INVALID_CONTEXT_MAP_KEY("Invalid credentials. Context map key '%s1' contains invalid characters."), - - // Bearer token generation - INVALID_BEARER_TOKEN("Bearer token is invalid or expired."), - INVALID_CREDENTIALS_FILE("Credentials file is either null or an invalid file."), - INVALID_CREDENTIALS_STRING("Credentials string is either null or empty."), - INVALID_CREDENTIALS_FILE_FORMAT("Credentials file is not in a valid JSON format."), - CREDENTIALS_FILE_NOT_FOUND("Credentials file not found at specified path."), - INVALID_CREDENTIALS_STRING_FORMAT("Credentials string is not in a valid JSON string format."), - PRIVATE_KEY_IS_REQUIRED("Private key is required."), - CLIENT_ID_IS_REQUIRED("Client ID is required."), - KEY_ID_IS_REQUIRED("Key ID is required."), - TOKEN_URI_IS_REQUIRED("Token URI is required."), - INVALID_TOKEN_URI("Invalid value for token URI in credentials."), - JWT_INVALID_FORMAT("Private key is not in a valid format."), - INVALID_ALGORITHM("Algorithm for parsing private key is invalid or does not exist."), - INVALID_KEY_SPEC("Unable to parse RSA private key."), - BEARER_TOKEN_REJECTED("Bearer token request resulted in failure."), - SIGNED_DATA_TOKENS_REJECTED("Signed data tokens request resulted in failure."), - - // Vault api interfaces - TABLE_IS_REQUIRED("Invalid %s1 request. Table is required."), - EMPTY_TABLE_NAME("Invalid %s1 request. Table name can not be empty."), - VALUES_IS_REQUIRED("Invalid %s1 request. Values are required."), - EMPTY_OR_NULL_KEY_IN_VALUES("Invalid %s1 request. Key can not be null or empty in values"), - EMPTY_UPSERT("Invalid %s1 request. Upsert can not be empty."), - HOMOGENOUS_NOT_SUPPORTED_WITH_UPSERT("Invalid %s1 request. Homogenous is not supported when upsert is passed."), - TOKENS_NOT_ALLOWED_WITH_TOKEN_MODE_DISABLE("Invalid %s1 request. Tokens are not allowed when tokenMode is DISABLE."), - TOKENS_REQUIRED_WITH_TOKEN_MODE("Invalid %s1 request. Tokens are required when tokenMode is %s2."), - EMPTY_TOKENS("Invalid %s1 request. Tokens can not be empty."), - EMPTY_OR_NULL_KEY_IN_TOKENS("Invalid %s1 request. Key can not be null or empty in tokens."), - INSUFFICIENT_TOKENS_PASSED_FOR_TOKEN_MODE_ENABLE_STRICT("Invalid %s1 request. For tokenMode as ENABLE_STRICT, tokens should be passed for all fields."), - MISMATCH_OF_FIELDS_AND_TOKENS("Invalid %s1 request. Keys for values and tokens are not matching."), - INSERT_RECORDS_REJECTED("Insert request resulted in failure."), - DETOKENIZE_DATA_REQUIRED("Invalid %s1 request. Detokenize data is required."), - EMPTY_DETOKENIZE_DATA("Invalid %s1 request. Detokenize data can not be empty."), - EMPTY_OR_NULL_TOKEN_IN_DETOKENIZE_DATA("Invalid %s1 request. Token can not be null or empty in detokenize data at index %s2."), - REDACTION_IS_REQUIRED("Invalid %s1 request. Redaction is required."), - DETOKENIZE_REQUEST_REJECTED("Detokenize request resulted in failure."), - IDS_IS_REQUIRED("Invalid %s1 request. Ids are required."), - EMPTY_IDS("Invalid %s1 request. Ids can not be empty."), - EMPTY_OR_NULL_ID_IN_IDS("Invalid %s1 request. Id can not be null or empty in ids at index %s2."), - EMPTY_FIELDS("Invalid %s1 request. Fields can not be empty."), - EMPTY_OR_NULL_FIELD_IN_FIELDS("Invalid %s1 request. Field can not be null or empty in fields at index %s2."), - TOKENIZATION_NOT_SUPPORTED_WITH_REDACTION("Invalid %s1 request. Return tokens is not supported when redaction is applied."), - TOKENIZATION_SUPPORTED_ONLY_WITH_IDS("Invalid %s1 request. Return tokens is not supported when column name and values are passed."), - EMPTY_OFFSET("Invalid %s1 request. Offset can not be empty."), - EMPTY_LIMIT("Invalid %s1 request. Limit can not be empty."), - NEITHER_IDS_NOR_COLUMN_NAME_PASSED("Invalid %s1 request. Neither ids nor column name and values are passed."), - BOTH_IDS_AND_COLUMN_NAME_PASSED("Invalid %s1 request. Both ids and column name and values are passed."), - COLUMN_NAME_IS_REQUIRED("Invalid %s1 request. Column name is required when column values are passed."), - EMPTY_COLUMN_NAME("Invalid %s1 request. Column name can not be empty."), - COLUMN_VALUES_IS_REQUIRED_GET("Invalid %s1 request. Column values are required when column name is passed."), - EMPTY_COLUMN_VALUES("Invalid %s1 request. Column values can not be empty."), - EMPTY_OR_NULL_COLUMN_VALUE_IN_COLUMN_VALUES("Invalid %s1 request. Column value can not by null or empty in column values at index %s2."), - GET_REQUEST_REJECTED("Get request resulted in failure."), - DATA_IS_REQUIRED("Invalid %s1 request. Data is required."), - EMPTY_DATA("Invalid %s1 request. Data can not be empty."), - SKYFLOW_ID_IS_REQUIRED("Invalid %s1 request. Skyflow Id is required."), - INVALID_SKYFLOW_ID_TYPE("Invalid %s1 request. Skyflow Id should of type String."), - EMPTY_SKYFLOW_ID("Invalid %s1 request. Skyflow Id can not be empty."), - UPDATE_REQUEST_REJECTED("Update request resulted in failure."), - QUERY_IS_REQUIRED("Invalid %s1 request. Query is required."), - EMPTY_QUERY("Invalid %s1 request. Query can not be empty."), - QUERY_REQUEST_REJECTED("Query request resulted in failure."), - COLUMN_VALUES_IS_REQUIRED_TOKENIZE("Invalid %s1 request. ColumnValues are required."), - EMPTY_OR_NULL_COLUMN_GROUP_IN_COLUMN_VALUES("Invalid %s1 request. Column group can not be null or empty in column values at index %s2."), - TOKENIZE_REQUEST_REJECTED("Tokenize request resulted in failure."), - DELETE_REQUEST_REJECTED("Delete request resulted in failure."), - - // invoke connection interface - INVOKE_CONNECTION_INVALID_CONNECTION_URL("Invalid %s1 request. Connection URL is not a valid URL."), - EMPTY_REQUEST_HEADERS("Invalid %s1 request. Request headers can not be empty."), - INVALID_REQUEST_HEADERS("Invalid %s1 request. Request header can not be null or empty in request headers."), - EMPTY_PATH_PARAMS("Invalid %s1 request. Path params can not be empty."), - INVALID_PATH_PARAM("Invalid %s1 request. Path parameter can not be null or empty in path params."), - EMPTY_QUERY_PARAMS("Invalid %s1 request. Query params can not be empty."), - INVALID_QUERY_PARAM("Invalid %s1 request. Query parameter can not be null or empty in query params."), - EMPTY_REQUEST_BODY("Invalid %s1 request. Request body can not be empty."), - INVALID_REQUEST_BODY("Invalid %s1 request. Request body can not be empty."), - INVOKE_CONNECTION_REQUEST_REJECTED("Invoke connection request resulted in failure."), - - // File upload interface - COLUMN_NAME_IS_REQUIRED_FILE_UPLOAD("Invalid %s1 request. Column name is required."), - EMPTY_COLUMN_NAME_FILE_UPLOAD("Invalid %s1 request. Column name can not be empty."), - FILE_IS_REQUIRED("Invalid %s1 request. File is required."), - EMPTY_FILE("Invalid %s1 request. File can not be empty."), - INVALID_FILE_TYPE("Invalid %s1 request. File should be of type java.io.File"), - MISSING_FILE_SOURCE_IN_UPLOAD_FILE("Invalid %s1 request. Provide exactly one of filePath, base64, or fileObject."), - UPLOAD_FILE_REQUEST_REJECTED("Upload file request resulted in failure."), - - - // detect interface - INVALID_TEXT_IN_DEIDENTIFY("Invalid %s1 request. The text field is required and must be a non-empty string. Specify a valid text."), - DEIDENTIFY_TEXT_REQUEST_REJECTED("DeIdentify text request resulted in failure."), - INVALID_TEXT_IN_REIDENTIFY("Invalid %s1 request. The text field is required and must be a non-empty string. Specify a valid text."), - REIDENTIFY_TEXT_REQUEST_REJECTED("ReIdentify text request resulted in failure."), - DEIDENTIFY_FILE_REQUEST_REJECTED("DeIdentify file request resulted in failure."), - GET_DETECT_RUN_REQUEST_REJECTED("Get detect run request resulted in failure."), - INVALID_NULL_FILE_IN_DEIDENTIFY_FILE("Invalid %s1 request. The file field is required and must not be null. Specify a valid file."), - FILE_NOT_FOUND_TO_DEIDENTIFY("Invalid %s1 request. The file field is required and must not be empty. Specify a valid file."), - FILE_NOT_READABLE_TO_DEIDENTIFY("Invalid %s1 request. The file is not readable. Please check the file permissions or path."), - INVALID_PIXEL_DENSITY_TO_DEIDENTIFY_FILE("Invalid %s1 request. Pixel density must be a positive integer greater than 0. Specify a valid pixel density."), - INVALID_MAX_RESOLUTION("Invalid %s1 request. Max resolution must be a positive integer greater than 0. Specify a valid max resolution."), - INVALID_BLEEP_TO_DEIDENTIFY_AUDIO("Invalid %s1 request. Specify a valid bleep as AudioBleep"), - OUTPUT_DIRECTORY_NOT_FOUND("Invalid %s1 request. The output directory does not exist. Please specify a valid output directory."), - INVALID_PERMISSIONS_FOR_OUTPUT_DIRECTORY("Invalid %s1 request. The output directory is not writable. Please check the permissions or specify a valid output directory."), - EMPTY_FILE_AND_FILE_PATH_IN_DEIDENTIFY_FILE("Invalid %s1 request. The file and file path fields are both empty. Specify a valid file object or file path."), - ; - - private final String log; - - ErrorLogs(String log) { - this.log = log; - } - - public final String getLog() { - return log; - } -} diff --git a/v2/src/main/java/com/skyflow/logs/InfoLogs.java b/v2/src/main/java/com/skyflow/logs/InfoLogs.java deleted file mode 100644 index e747bfa2..00000000 --- a/v2/src/main/java/com/skyflow/logs/InfoLogs.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.skyflow.logs; - -public enum InfoLogs { - // Client initialization - CLIENT_INITIALIZED("Initialized skyflow client."), - VALIDATING_VAULT_CONFIG("Validating vault config."), - VALIDATING_CONNECTION_CONFIG("Validating connection config."), - UNABLE_TO_GENERATE_SDK_METRIC("Unable to generate %s1 metric."), - VAULT_CONTROLLER_INITIALIZED("Initialized vault controller with vault ID %s1."), - DETECT_CONTROLLER_INITIALIZED("Initialized detect controller with vault ID %s1."), - CONNECTION_CONTROLLER_INITIALIZED("Initialized connection controller with connection ID %s1."), - LOGGER_SETUP_DONE("Set up logger."), - CURRENT_LOG_LEVEL("Current log level is %s1."), - - // Bearer token generation - EMPTY_BEARER_TOKEN("Bearer token is empty."), - BEARER_TOKEN_EXPIRED("Bearer token is invalid or expired."), - GET_BEARER_TOKEN_TRIGGERED("getBearerToken method triggered."), - GET_BEARER_TOKEN_SUCCESS("Bearer token generated."), - GET_SIGNED_DATA_TOKENS_TRIGGERED("getSignedDataTokens method triggered."), - GET_SIGNED_DATA_TOKEN_SUCCESS("Signed data tokens generated."), - REUSE_BEARER_TOKEN("Reusing bearer token."), - REUSE_API_KEY("Reusing api key."), - GENERATE_BEARER_TOKEN_FROM_CREDENTIALS_TRIGGERED("generateBearerTokenFromCredentials method triggered."), - GENERATE_BEARER_TOKEN_FROM_CREDENTIALS_STRING_TRIGGERED("generateBearerTokenFromCredentialString method triggered."), - GENERATE_SIGNED_TOKENS_FROM_CREDENTIALS_FILE_TRIGGERED("generateSignedTokensFromCredentialsFile method triggered."), - GENERATE_SIGNED_TOKENS_FROM_CREDENTIALS_STRING_TRIGGERED("generateSignedTokensFromCredentialsString method triggered."), - - // Insert interface - INSERT_TRIGGERED("Insert method triggered."), - VALIDATE_INSERT_REQUEST("Validating insert request."), - INSERT_REQUEST_RESOLVED("Insert request resolved."), - INSERT_SUCCESS("Data inserted."), - - // Detokenize interface - DETOKENIZE_TRIGGERED("Detokenize method triggered."), - VALIDATE_DETOKENIZE_REQUEST("Validating detokenize request."), - DETOKENIZE_REQUEST_RESOLVED("Detokenize request resolved."), - DETOKENIZE_PARTIAL_SUCCESS("Data detokenized partially."), - DETOKENIZE_SUCCESS("Data detokenized."), - - // Get interface - GET_TRIGGERED("Get method triggered."), - VALIDATE_GET_REQUEST("Validating get request."), - GET_REQUEST_RESOLVED("Get request resolved."), - GET_SUCCESS("Data revealed."), - - // Update interface - UPDATE_TRIGGERED("Update method triggered."), - VALIDATE_UPDATE_REQUEST("Validating update request."), - UPDATE_REQUEST_RESOLVED("Update request resolved."), - UPDATE_SUCCESS("Data updated."), - - // Delete interface - DELETE_TRIGGERED("Delete method triggered."), - VALIDATING_DELETE_REQUEST("Validating delete request."), - DELETE_REQUEST_RESOLVED("Delete request resolved."), - DELETE_SUCCESS("Data deleted."), - - // Query interface - QUERY_TRIGGERED("Query method triggered."), - VALIDATING_QUERY_REQUEST("Validating query request."), - QUERY_REQUEST_RESOLVED("Query request resolved."), - QUERY_SUCCESS("Query executed."), - - // Tokenize interface - TOKENIZE_TRIGGERED("Tokenize method triggered."), - VALIDATING_TOKENIZE_REQUEST("Validating tokenize request."), - TOKENIZE_REQUEST_RESOLVED("Tokenize request resolved."), - TOKENIZE_SUCCESS("Data tokenized."), - - // File upload interface - FILE_UPLOAD_TRIGGERED("File upload method triggered."), - VALIDATING_FILE_UPLOAD_REQUEST("Validating file upload request."), - FILE_UPLOAD_REQUEST_RESOLVED("File upload request resolved."), - FILE_UPLOAD_SUCCESS("File uploaded successfully."), - - // Invoke connection interface - INVOKE_CONNECTION_TRIGGERED("Invoke connection method triggered."), - VALIDATING_INVOKE_CONNECTION_REQUEST("Validating invoke connection request."), - INVOKE_CONNECTION_REQUEST_RESOLVED("Invoke connection request resolved."), - - // detect - VALIDATE_DEIDENTIFY_TEXT_REQUEST("Validating deidentify text request."), - DEIDENTIFY_TEXT_SUCCESS("Text data de-identified."), - DEIDENTIFY_TEXT_TRIGGERED("DeIdentify text method triggered."), - DEIDENTIFY_TEXT_REQUEST_RESOLVED("DeIdentify text request resolved."), - VALIDATE_REIDENTIFY_TEXT_REQUEST("Validating reidentify text request."), - REIDENTIFY_TEXT_TRIGGERED("ReIdentify text method triggered."), - REIDENTIFY_TEXT_REQUEST_RESOLVED("ReIdentify text request resolved."), - DEIDENTIFY_FILE_TRIGGERED("DeIdentify file method triggered."), - VALIDATE_DEIDENTIFY_FILE_REQUEST("Validating deidentify file request."), - DEIDENTIFY_FILE_REQUEST_RESOLVED("DeIdentify file request resolved."), - DEIDENTIFY_FILE_SUCCESS("File deidentified successfully."), - GET_DETECT_RUN_TRIGGERED("Get detect run method triggered."), - VALIDATE_GET_DETECT_RUN_REQUEST("Validating get detect run request."), - REIDENTIFY_TEXT_SUCCESS("Text data re-identified."), - - // Deprecation warnings — v2 backward compat - DEPRECATED_SKYFLOW_ID_KEY("[DEPRECATED] Response key 'skyflow_id' is deprecated and will be removed in an upcoming release. Use 'skyflowId' instead."), - DEPRECATED_SKYFLOW_ID_REQUEST_KEY("[DEPRECATED] Request data key 'skyflow_id' is deprecated and will be removed in an upcoming release. Use 'skyflowId' instead."), - DEPRECATED_DOWNLOAD_URL("[DEPRECATED] Method 'downloadURL()' is deprecated and will be removed in an upcoming release. Use 'downloadUrl()' instead."), - DEPRECATED_GET_BYOT("[DEPRECATED] Method 'getBYOT()' is deprecated and will be removed in an upcoming release. Use 'getByot()' instead."), - DEPRECATED_UPDATE_LOG_LEVEL("[DEPRECATED] Method 'updateLogLevel()' is deprecated and will be removed in an upcoming release. Use 'setLogLevel()' instead."), - DEPRECATED_CREDENTIAL_CLIENT_ID("[DEPRECATED] Credential field 'clientID' is deprecated and will be removed in an upcoming release. Use 'clientId' instead."), - DEPRECATED_CREDENTIAL_KEY_ID("[DEPRECATED] Credential field 'keyID' is deprecated and will be removed in an upcoming release. Use 'keyId' instead."), - DEPRECATED_CREDENTIAL_TOKEN_URI("[DEPRECATED] Credential field 'tokenURI' is deprecated and will be removed in an upcoming release. Use 'tokenUri' instead."); - - - - private final String log; - - InfoLogs(String log) { - this.log = log; - } - - public final String getLog() { - return log; - } -} diff --git a/v2/src/main/java/com/skyflow/vault/data/InsertResponse.java b/v2/src/main/java/com/skyflow/vault/data/InsertResponse.java index 3d311525..bc09b0c2 100644 --- a/v2/src/main/java/com/skyflow/vault/data/InsertResponse.java +++ b/v2/src/main/java/com/skyflow/vault/data/InsertResponse.java @@ -5,26 +5,8 @@ import java.util.ArrayList; import java.util.HashMap; -public class InsertResponse { - private final ArrayList> insertedFields; - private final ArrayList> errors; - +public class InsertResponse extends BaseInsertResponse { public InsertResponse(ArrayList> insertedFields, ArrayList> errors) { - this.insertedFields = insertedFields; - this.errors = errors; - } - - public ArrayList> getInsertedFields() { - return insertedFields; - } - - public ArrayList> getErrors() { - return errors; - } - - @Override - public String toString() { - Gson gson = new Gson().newBuilder().serializeNulls().create(); - return gson.toJson(this); + super(insertedFields, errors); } } diff --git a/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java index 0e1b6b63..0353aa6c 100644 --- a/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java +++ b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeData.java @@ -1,23 +1,23 @@ package com.skyflow.vault.tokens; import com.skyflow.enums.RedactionType; +import com.skyflow.vault.data.BaseDetokenizeData; -public class DetokenizeData { - private final String token; +public class DetokenizeData extends BaseDetokenizeData { private final RedactionType redactionType; public DetokenizeData(String token) { - this.token = token; + super(token); this.redactionType = RedactionType.DEFAULT; } public DetokenizeData(String token, RedactionType redactionType) { - this.token = token; - this.redactionType = redactionType == null ? RedactionType.DEFAULT : redactionType; + super(token); + this.redactionType = redactionType == null ? RedactionType.DEFAULT : redactionType; } public String getToken() { - return this.token; + return super.getToken(); } public RedactionType getRedactionType() { diff --git a/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java index 7d2ae73c..a16b17dd 100644 --- a/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java +++ b/v2/src/main/java/com/skyflow/vault/tokens/DetokenizeRecordResponse.java @@ -2,44 +2,29 @@ import com.skyflow.generated.rest.types.V1DetokenizeRecordResponse; +import com.skyflow.vault.data.BaseDetokenizeRecordResponse; -public class DetokenizeRecordResponse { - private final String token; - private final String value; +public class DetokenizeRecordResponse extends BaseDetokenizeRecordResponse { private final String type; - private final String error; private final String requestId; + private final String value; public DetokenizeRecordResponse(V1DetokenizeRecordResponse record) { this(record, null); } public DetokenizeRecordResponse(V1DetokenizeRecordResponse record, String requestId) { - this.token = record.getToken().orElse(null); - + super(record.getToken().orElse(null), record.getError().orElse(null)); this.value = record.getValue() .filter(val -> val != null && !val.toString().isEmpty()) .orElse(null); - this.type = record.getValueType() .map(Enum::toString) .filter(val -> !"NONE".equals(val)) .orElse(null); - this.error = record.getError().orElse(null); - this.requestId = requestId; } - - - public String getError() { - return error; - } - - public String getToken() { - return token; - } - public String getValue() { return value; } diff --git a/v2/src/test/java/com/skyflow/SkyflowTests.java b/v2/src/test/java/com/skyflow/SkyflowTests.java index f73b5bb0..07386a5b 100644 --- a/v2/src/test/java/com/skyflow/SkyflowTests.java +++ b/v2/src/test/java/com/skyflow/SkyflowTests.java @@ -103,55 +103,6 @@ public void testAddingValidVaultConfigInSkyflowClient() { } } - @Test - public void testAddingExistingVaultConfigInSkyflowClient() { - try { - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultID); - config.setClusterId(clusterID); - config.setEnv(Env.SANDBOX); - Skyflow skyflowClient = Skyflow.builder().build(); - skyflowClient.addVaultConfig(config).addVaultConfig(config); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.VaultIdAlreadyInConfigList.getMessage(), e.getMessage()); - } - } - - @Test - public void testUpdatingNonExistentVaultConfigInSkyflowBuilder() { - try { - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultID); - config.setClusterId(clusterID); - config.setEnv(Env.SANDBOX); - Skyflow.builder().updateVaultConfig(config).build(); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); - } - } - - @Test - public void testUpdatingNonExistentVaultConfigInSkyflowClient() { - try { - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultID); - config.setClusterId(clusterID); - config.setEnv(Env.SANDBOX); - Skyflow skyflowClient = Skyflow.builder().build(); - skyflowClient.updateVaultConfig(config); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); - } catch (Exception e) { - Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); - } - } - @Test public void testUpdatingValidVaultConfigInSkyflowClient() { try { @@ -174,114 +125,6 @@ public void testUpdatingValidVaultConfigInSkyflowClient() { } } - @Test - public void testUpdateVaultConfigNullCredentialsFallsBackToPrevious() { - try { - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultID); - config.setClusterId(clusterID); - config.setEnv(Env.SANDBOX); - - Credentials creds = new Credentials(); - creds.setToken(token); - config.setCredentials(creds); - - Skyflow skyflowClient = Skyflow.builder().addVaultConfig(config).build(); - - // Update with null credentials — should retain previous credentials value - VaultConfig partialUpdate = new VaultConfig(); - partialUpdate.setVaultId(vaultID); - partialUpdate.setClusterId(clusterID); - skyflowClient.updateVaultConfig(partialUpdate); - Assert.assertNotNull(skyflowClient.getVaultConfig(vaultID).getCredentials()); - } catch (SkyflowException e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testRemovingNonExistentVaultConfigInSkyflowBuilder() { - try { - Skyflow.builder().removeVaultConfig(vaultID).build(); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); - } - } - - @Test - public void testRemovingNonExistentVaultConfigInSkyflowClient() { - try { - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultID); - config.setClusterId(clusterID); - config.setEnv(Env.SANDBOX); - Skyflow skyflowClient = Skyflow.builder().addVaultConfig(config).build(); - skyflowClient.removeVaultConfig(vaultID); - } catch (SkyflowException e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testRemovingValidVaultConfigInSkyflowClient() { - try { - Skyflow skyflowClient = Skyflow.builder().build(); - skyflowClient.removeVaultConfig(vaultID); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); - } - } - - @Test - public void testGettingNonExistentVaultConfigInSkyflowClient() { - try { - Skyflow skyflowClient = Skyflow.builder().build(); - VaultConfig config = skyflowClient.getVaultConfig(vaultID); - Assert.assertNull(config); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testGettingAlreadyRemovedVaultFromEmptyConfigs() { - try { - Skyflow skyflowClient = Skyflow.builder().build(); - skyflowClient.vault(); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); - } - } - - @Test - public void testGettingAlreadyRemovedVaultFromNonEmptyConfigs() { - try { - VaultConfig primaryConfig = new VaultConfig(); - primaryConfig.setVaultId(vaultID); - primaryConfig.setClusterId(clusterID); - primaryConfig.setEnv(Env.SANDBOX); - - VaultConfig secondaryConfig = new VaultConfig(); - secondaryConfig.setVaultId(vaultID + "123"); - secondaryConfig.setClusterId(clusterID); - secondaryConfig.setEnv(Env.SANDBOX); - Skyflow skyflowClient = Skyflow.builder().addVaultConfig(primaryConfig).addVaultConfig(secondaryConfig).build(); - skyflowClient.removeVaultConfig(vaultID); - skyflowClient.vault(vaultID); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.VaultIdNotInConfigList.getMessage(), e.getMessage()); - } - } - - @Test public void testAddingInvalidConnectionConfigInSkyflowBuilder() { try { @@ -461,60 +304,6 @@ public void testGettingNonExistentConnectionConfigInSkyflowClient() { } } - @Test - public void testAddingInvalidSkyflowCredentialsInSkyflowBuilder() { - try { - Credentials credentials = new Credentials(); - Skyflow.builder().addSkyflowCredentials(credentials).build(); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.NoTokenGenerationMeansPassed.getMessage(), e.getMessage()); - } - } - - @Test - public void testUpdatingValidSkyflowCredentialsInSkyflowClient() { - try { - VaultConfig vaultConfig = new VaultConfig(); - vaultConfig.setVaultId(vaultID); - vaultConfig.setClusterId(clusterID); - - ConnectionConfig connectionConfig = new ConnectionConfig(); - connectionConfig.setConnectionId(connectionID); - connectionConfig.setConnectionUrl(connectionURL); - - Credentials credentials = new Credentials(); - credentials.setToken(token); - Skyflow skyflowClient = Skyflow.builder().addVaultConfig(vaultConfig).addConnectionConfig(connectionConfig).build(); - skyflowClient.updateSkyflowCredentials(credentials); - } catch (SkyflowException e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testDefaultLogLevel() { - try { - Skyflow skyflowClient = Skyflow.builder().setLogLevel(null).build(); - Assert.assertEquals(LogLevel.ERROR, skyflowClient.getLogLevel()); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testSetLogLevel() { - try { - Skyflow skyflowClient = Skyflow.builder().setLogLevel(LogLevel.INFO).build(); - Assert.assertEquals(LogLevel.INFO, skyflowClient.getLogLevel()); - skyflowClient.setLogLevel(LogLevel.WARN); - Assert.assertEquals(LogLevel.WARN, skyflowClient.getLogLevel()); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - @Test @SuppressWarnings("deprecation") public void testUpdateLogLevel() { @@ -687,36 +476,6 @@ public void testDetectMethodWithInvalidVaultId() { } } - @Test - public void testUpdateVaultConfig_withNewClusterIdAndCredentials_updatesAllFields() { - try { - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultID); - config.setClusterId(clusterID); - config.setEnv(Env.DEV); - Credentials creds = new Credentials(); - creds.setToken(token); - config.setCredentials(creds); - Skyflow skyflowClient = Skyflow.builder().addVaultConfig(config).build(); - - // Update with a new non-null clusterId and new non-null credentials — covers - // the non-null (true) branches for all three ternaries in findAndUpdateVaultConfig - Credentials newCreds = new Credentials(); - newCreds.setToken("updated-token-value"); - VaultConfig update = new VaultConfig(); - update.setVaultId(vaultID); - update.setClusterId(newClusterID); - update.setEnv(Env.PROD); - update.setCredentials(newCreds); - skyflowClient.updateVaultConfig(update); - Assert.assertEquals(newClusterID, skyflowClient.getVaultConfig(vaultID).getClusterId()); - Assert.assertEquals(Env.PROD, skyflowClient.getVaultConfig(vaultID).getEnv()); - Assert.assertEquals("updated-token-value", skyflowClient.getVaultConfig(vaultID).getCredentials().getToken()); - } catch (SkyflowException e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - @Test public void testUpdateConnectionConfig_withNewCredentials_updatesCredentials() { try { @@ -744,75 +503,6 @@ public void testUpdateConnectionConfig_withNewCredentials_updatesCredentials() { } } - @Test - public void testUpdateVaultConfig_withNullEnv_fallsBackToPreviousEnv() { - // VaultConfig's constructor defaults env=PROD so getEnv() is never null via normal API. - // Use an anonymous subclass to make getEnv() return null, exercising the false branch - // of `vaultConfig.getEnv() != null` in findAndUpdateVaultConfig. - try { - Credentials creds = new Credentials(); - creds.setToken(token); - VaultConfig initial = new VaultConfig(); - initial.setVaultId(vaultID); - initial.setClusterId(clusterID); - initial.setEnv(Env.SANDBOX); - initial.setCredentials(creds); - Skyflow skyflowClient = Skyflow.builder().addVaultConfig(initial).build(); - - VaultConfig updateWithNullEnv = new VaultConfig() { - @Override public Env getEnv() { return null; } - }; - updateWithNullEnv.setVaultId(vaultID); - updateWithNullEnv.setClusterId(clusterID); - updateWithNullEnv.setCredentials(creds); - - skyflowClient.updateVaultConfig(updateWithNullEnv); - // env falls back to previous (SANDBOX) - Assert.assertEquals(Env.SANDBOX, skyflowClient.getVaultConfig(vaultID).getEnv()); - } catch (SkyflowException e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testFindAndUpdateVaultConfig_withNullClusterId_fallsBackToPreviousClusterId() { - // Validation enforces non-null clusterId, so the false branch of - // `vaultConfig.getClusterId() != null` in findAndUpdateVaultConfig is unreachable - // via the normal flow. Call the private method directly via reflection. - try { - Credentials creds = new Credentials(); - creds.setToken(token); - VaultConfig initial = new VaultConfig(); - initial.setVaultId(vaultID); - initial.setClusterId(clusterID); - initial.setEnv(Env.DEV); - initial.setCredentials(creds); - Skyflow skyflowClient = Skyflow.builder().addVaultConfig(initial).build(); - - java.lang.reflect.Field builderField = Skyflow.class.getDeclaredField("builder"); - builderField.setAccessible(true); - Object builder = builderField.get(skyflowClient); - - VaultConfig nullClusterConfig = new VaultConfig(); - nullClusterConfig.setVaultId(vaultID); - // Override clusterId field to null via reflection (setter enforces non-null) - java.lang.reflect.Field clusterIdField = VaultConfig.class.getDeclaredField("clusterId"); - clusterIdField.setAccessible(true); - clusterIdField.set(nullClusterConfig, null); - - java.lang.reflect.Method method = builder.getClass().getDeclaredMethod( - "findAndUpdateVaultConfig", VaultConfig.class); - method.setAccessible(true); - VaultConfig result = (VaultConfig) method.invoke(builder, nullClusterConfig); - - Assert.assertEquals(clusterID, result.getClusterId()); - } catch (SkyflowException e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } catch (Exception e) { - Assert.fail("Reflection failed: " + e.getMessage()); - } - } - @Test public void testFindAndUpdateConnectionConfig_withNullConnectionUrl_fallsBackToPreviousUrl() { // `findAndUpdateConnectionConfig` has a ternary for connectionUrl that falls back diff --git a/v2/src/test/java/com/skyflow/VaultClientDotenvTests.java b/v2/src/test/java/com/skyflow/VaultClientDotenvTests.java deleted file mode 100644 index 2e71816a..00000000 --- a/v2/src/test/java/com/skyflow/VaultClientDotenvTests.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.skyflow; - -import com.skyflow.config.BaseVaultConfig; -import com.skyflow.config.Credentials; -import com.skyflow.config.VaultConfig; -import com.skyflow.enums.Env; -import com.skyflow.errors.ErrorMessage; -import com.skyflow.errors.SkyflowException; -import com.skyflow.utils.Constants; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; - -/** - * Tests for VaultClient's prioritiseCredentials dotenv path. - * - * These tests write a temporary .env file to exercise the code path where - * no VaultConfig credentials and no common credentials are set, so the code - * falls through to read from a .env file. - */ -public class VaultClientDotenvTests { - - private static final String ENV_FILE = ".env"; - private byte[] originalEnvContent; - - @Before - public void saveEnvFileState() throws IOException { - File f = new File(ENV_FILE); - originalEnvContent = f.exists() ? Files.readAllBytes(Paths.get(ENV_FILE)) : null; - } - - @After - public void restoreEnvFile() throws IOException { - if (originalEnvContent != null) { - Files.write(Paths.get(ENV_FILE), originalEnvContent); - } else { - Files.deleteIfExists(Paths.get(ENV_FILE)); - } - } - - private VaultClient buildClientWithNoCreds(String vaultId, String clusterId) { - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultId); - config.setClusterId(clusterId); - config.setEnv(Env.DEV); - // No credentials set - return new VaultClient(config, null); - } - - /** - * Covers the dotenv success path: Dotenv.load() succeeds and returns a - * non-null credentials string, so finalCredentials is set via - * credentialsString. Lines ~862-870 of VaultClient.java. - */ - @Test - public void testPrioritiseCredentials_dotenvReturnsCredentials_setsCredentials() throws Exception { - // Write a .env file with a valid credentials string value - try (FileWriter fw = new FileWriter(ENV_FILE)) { - fw.write(Constants.ENV_CREDENTIALS_KEY_NAME + "={\"token\":\"env-token-value\"}\n"); - } - - VaultClient client = buildClientWithNoCreds("dotenv-vault-1", "cluster1"); - // updateVaultConfig() calls prioritiseCredentials() which reads from .env - // Should not throw since sysCredentials is non-null - client.updateVaultConfig(); - - // finalCredentials should be set with credentials string - java.lang.reflect.Field field = VaultClient.class.getDeclaredField("finalCredentials"); - field.setAccessible(true); - Credentials finalCreds = (Credentials) field.get(client); - Assert.assertNotNull(finalCreds); - Assert.assertEquals("{\"token\":\"env-token-value\"}", finalCreds.getCredentialsString()); - } - - /** - * Covers the path where dotenv loads but the key is absent (returns null), - * causing SkyflowException(EmptyCredentials) to be thrown directly. - * Lines ~864-876 of VaultClient.java. - */ - @Test - public void testPrioritiseCredentials_dotenvKeyMissing_throwsSkyflowException() throws Exception { - // Write a .env file WITHOUT the SKYFLOW_CREDENTIALS key - try (FileWriter fw = new FileWriter(ENV_FILE)) { - fw.write("SOME_OTHER_KEY=some_value\n"); - } - - VaultClient client = buildClientWithNoCreds("dotenv-vault-2", "cluster2"); - try { - client.updateVaultConfig(); - Assert.fail("Should have thrown SkyflowException"); - } catch (SkyflowException e) { - Assert.assertTrue(e.getMessage().contains(ErrorMessage.EmptyCredentials.getMessage())); - } catch (RuntimeException e) { - Assert.fail("Expected direct SkyflowException, not RuntimeException wrapping it"); - } - } -} diff --git a/v2/src/test/java/com/skyflow/VaultClientTests.java b/v2/src/test/java/com/skyflow/VaultClientTests.java index db04cae4..4c040ad0 100644 --- a/v2/src/test/java/com/skyflow/VaultClientTests.java +++ b/v2/src/test/java/com/skyflow/VaultClientTests.java @@ -1,6 +1,7 @@ package com.skyflow; import com.skyflow.config.VaultConfig; +import com.skyflow.config.BaseCredentials; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.*; @@ -900,44 +901,16 @@ public void testMapAudioDataFormat_invalid() throws Exception { } } - @Test - public void testPrioritiseCredentials_VaultConfigCredentials() throws Exception { - Credentials creds = new Credentials(); - creds.setApiKey("test_api_key"); - vaultConfig.setCredentials(creds); - - java.lang.reflect.Method method = VaultClient.class.getDeclaredMethod("prioritiseCredentials"); - method.setAccessible(true); - method.invoke(vaultClient); - - Assert.assertEquals(creds, getPrivateField(vaultClient, "finalCredentials")); - } - - @Test - public void testPrioritiseCredentials_CommonCredentials() throws Exception { - vaultConfig.setCredentials(null); - Credentials creds = new Credentials(); - creds.setApiKey("common_api_key"); - setPrivateField(vaultClient, "commonCredentials", creds); - - java.lang.reflect.Method method = VaultClient.class.getDeclaredMethod("prioritiseCredentials"); - method.setAccessible(true); - method.invoke(vaultClient); - - Assert.assertEquals(creds, getPrivateField(vaultClient, "finalCredentials")); - } - - // Helper methods for reflection field access - private Object getPrivateField(Object obj, String fieldName) throws Exception { - java.lang.reflect.Field field = obj.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(obj); - } - - private void setPrivateField(Object obj, String fieldName, Object value) throws Exception { - java.lang.reflect.Field field = obj.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - field.set(obj, value); + // Fields moved to base classes (e.g. common.BaseVaultClient) aren't found by + // getDeclaredField on the subclass, so walk up the hierarchy. + private java.lang.reflect.Field findDeclaredField(Class clazz, String fieldName) throws NoSuchFieldException { + for (Class current = clazz; current != null; current = current.getSuperclass()) { + try { + return current.getDeclaredField(fieldName); + } catch (NoSuchFieldException ignored) { + } + } + throw new NoSuchFieldException(fieldName); } @Test @@ -957,31 +930,6 @@ public void testGetFileForFileUpload_withFileObject() { } } - @Test - public void testSetBearerToken_validNonExpiredToken_reusesToken() { - try { - // far-future JWT: header.payload.sig where payload base64 decodes to {"exp":9999999999} - Credentials creds = new Credentials(); - creds.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); - VaultConfig config = new VaultConfig(); - config.setVaultId(vaultID); - config.setClusterId(clusterID); - config.setEnv(com.skyflow.enums.Env.DEV); - config.setCredentials(creds); - VaultClient freshClient = new VaultClient(config, null); - - // First call: token=null → generates from creds.getToken() - freshClient.setBearerToken(); - Assert.assertEquals("x.eyJleHAiOjk5OTk5OTk5OTl9.y", getPrivateField(freshClient, "token")); - - // Second call: token valid, not expired → REUSE_BEARER_TOKEN else branch - freshClient.setBearerToken(); - Assert.assertEquals("x.eyJleHAiOjk5OTk5OTk5OTl9.y", getPrivateField(freshClient, "token")); - } catch (Exception e) { - Assert.fail("Should not have thrown: " + e.getMessage()); - } - } - @Test public void testGetDeidentifyImageRequest_withMaskingMethod() { try { @@ -1043,52 +991,6 @@ public void testGetDeIdentifyTextResponse_withEntityScores() { Assert.assertEquals(0.95, result.getEntities().get(0).getScores().get("EMAIL_ADDRESS"), 0.001); } - @Test - public void testPrioritiseCredentials_credentialChange_resetsTokenAndApiKey() { - try { - Credentials credentialsA = new Credentials(); - credentialsA.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); - VaultConfig config = new VaultConfig(); - config.setVaultId("isolated-vault-change"); - config.setClusterId(clusterID); - config.setEnv(com.skyflow.enums.Env.DEV); - config.setCredentials(credentialsA); - VaultClient freshClient = new VaultClient(config, null); - - freshClient.updateVaultConfig(); // sets finalCredentials = credentialsA - setPrivateField(freshClient, "token", "cached-token"); // simulate prior auth - - Credentials credentialsB = new Credentials(); - credentialsB.setToken("other-token"); - config.setCredentials(credentialsB); - - freshClient.updateVaultConfig(); // original=A, new=B → different → reset token/apiKey - Assert.assertNull(getPrivateField(freshClient, "token")); - Assert.assertNull(getPrivateField(freshClient, "apiKey")); - } catch (Exception e) { - Assert.fail("Should not have thrown: " + e.getMessage()); - } - } - - @Test - public void testSetBearerToken_noCredentials_throwsEmptyCredentials() { - VaultConfig config = new VaultConfig(); - config.setVaultId("isolated-vault-nocreds"); - config.setClusterId(clusterID); - config.setEnv(com.skyflow.enums.Env.DEV); - // No credentials — will hit dotenv path → DotenvException → SkyflowException(EmptyCredentials) - VaultClient freshClient = new VaultClient(config, null); - try { - freshClient.setBearerToken(); - Assert.fail("Should have thrown SkyflowException"); - } catch (SkyflowException e) { - // SkyflowException expected — message varies by environment - // (EmptyCredentials when no .env, or credential error when .env provides creds) - } catch (Exception e) { - Assert.fail("Expected SkyflowException, got: " + e.getClass().getName() + ": " + e.getMessage()); - } - } - @Test public void testUpdateExecutorInHTTP_interceptorAddsAuthorizationHeader() { try { @@ -1104,7 +1006,7 @@ public void testUpdateExecutorInHTTP_interceptorAddsAuthorizationHeader() { freshClient.setBearerToken(); // triggers updateExecutorInHTTP → creates sharedHttpClient with interceptor // Access sharedHttpClient via reflection - java.lang.reflect.Field field = VaultClient.class.getDeclaredField("sharedHttpClient"); + java.lang.reflect.Field field = findDeclaredField(VaultClient.class, "sharedHttpClient"); field.setAccessible(true); OkHttpClient httpClient = (OkHttpClient) field.get(freshClient); Assert.assertNotNull(httpClient); diff --git a/v2/src/test/java/com/skyflow/config/VaultConfigTests.java b/v2/src/test/java/com/skyflow/config/VaultConfigTests.java index 31305c0c..b99f6c9b 100644 --- a/v2/src/test/java/com/skyflow/config/VaultConfigTests.java +++ b/v2/src/test/java/com/skyflow/config/VaultConfigTests.java @@ -30,7 +30,7 @@ public static void setup() { @Test public void testValidVaultConfigWithCredentialsInValidations() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -49,7 +49,7 @@ public void testValidVaultConfigWithCredentialsInValidations() { @Test public void testValidVaultConfigWithoutCredentialsInValidations() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -67,7 +67,7 @@ public void testValidVaultConfigWithoutCredentialsInValidations() { @Test public void testDefaultEnvInVaultConfigWithCredentialsInValidations() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setCredentials(credentials); @@ -85,7 +85,7 @@ public void testDefaultEnvInVaultConfigWithCredentialsInValidations() { @Test public void testDefaultEnvInVaultConfigWithoutCredentialsInValidations() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(null); @@ -102,7 +102,7 @@ public void testDefaultEnvInVaultConfigWithoutCredentialsInValidations() { @Test public void testNoVaultIdInVaultConfigInValidations() { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); try { vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -117,7 +117,7 @@ public void testNoVaultIdInVaultConfigInValidations() { @Test public void testEmptyVaultIdInVaultConfigInValidations() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(""); vaultConfig.setClusterId(clusterID); vaultConfig.setEnv(Env.SANDBOX); @@ -132,7 +132,7 @@ public void testEmptyVaultIdInVaultConfigInValidations() { @Test public void testNoClusterIdInVaultConfigInValidations() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setEnv(Env.SANDBOX); Validations.validateVaultConfig(vaultConfig); @@ -146,7 +146,7 @@ public void testNoClusterIdInVaultConfigInValidations() { @Test public void testEmptyClusterIdInVaultConfigInValidations() { try { - BaseVaultConfig vaultConfig = new BaseVaultConfig(); + VaultConfig vaultConfig = new VaultConfig(); vaultConfig.setVaultId(vaultID); vaultConfig.setClusterId(""); vaultConfig.setEnv(Env.SANDBOX); diff --git a/v2/src/test/java/com/skyflow/utils/UtilsTests.java b/v2/src/test/java/com/skyflow/utils/UtilsTests.java index 4e910e15..d1e1c725 100644 --- a/v2/src/test/java/com/skyflow/utils/UtilsTests.java +++ b/v2/src/test/java/com/skyflow/utils/UtilsTests.java @@ -2,31 +2,17 @@ import com.google.gson.JsonObject; import com.skyflow.config.ConnectionConfig; -import com.skyflow.config.Credentials; -import com.skyflow.enums.Env; import com.skyflow.enums.RequestMethod; -import com.skyflow.errors.ErrorCode; -import com.skyflow.errors.ErrorMessage; -import com.skyflow.errors.SkyflowException; import com.skyflow.vault.connection.InvokeConnectionRequest; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class UtilsTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; - private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; - private static String clusterId = null; - private static String url = null; - private static String filePath = null; - private static String credentialsString = null; - private static String token = null; - private static String context = null; - private static ArrayList roles = null; private static String connectionId = null; private static String connectionUrl = null; private static Map queryParams; @@ -35,15 +21,6 @@ public class UtilsTests { @BeforeClass public static void setup() { - clusterId = "test_cluster_id"; - url = "https://test-url.com/java/unit/tests"; - filePath = "invalid/file/path/credentials.json"; - credentialsString = "invalid credentials string"; - token = "invalid-token"; - context = "test_context"; - roles = new ArrayList<>(); - String role = "test_role"; - roles.add(role); connectionId = "test_connection_id"; connectionUrl = "https://test.connection.url"; pathParams = new HashMap<>(); @@ -51,108 +28,6 @@ public static void setup() { requestHeaders = new HashMap<>(); } - @Test - public void testGetVaultURLForDev() { - try { - String vaultURL = Utils.getVaultURL(clusterId, Env.DEV); - String devUrl = "https://test_cluster_id.vault.skyflowapis.dev"; - Assert.assertEquals(devUrl, vaultURL); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testGetVaultURLForStage() { - try { - String vaultURL = Utils.getVaultURL(clusterId, Env.STAGE); - String stageUrl = "https://test_cluster_id.vault.skyflowapis.tech"; - Assert.assertEquals(stageUrl, vaultURL); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testGetVaultURLForSandbox() { - try { - String vaultURL = Utils.getVaultURL(clusterId, Env.SANDBOX); - String sandboxUrl = "https://test_cluster_id.vault.skyflowapis-preview.com"; - Assert.assertEquals(sandboxUrl, vaultURL); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testGetVaultURLForProd() { - try { - String vaultURL = Utils.getVaultURL(clusterId, Env.PROD); - String prodUrl = "https://test_cluster_id.vault.skyflowapis.com"; - Assert.assertEquals(prodUrl, vaultURL); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testGetBaseURL() { - try { - String baseURL = Utils.getBaseURL(url); - String url = "https://test-url.com"; - Assert.assertEquals(url, baseURL); - } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - - @Test - public void testGenerateBearerTokenWithCredentialsFile() { - try { - Credentials credentials = new Credentials(); - credentials.setPath(filePath); - credentials.setContext(context); - credentials.setRoles(roles); - Utils.generateBearerToken(credentials); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), filePath), - e.getMessage() - ); - } - } - - @Test - public void testGenerateBearerTokenWithCredentialsString() { - try { - Credentials credentials = new Credentials(); - credentials.setCredentialsString(credentialsString); - credentials.setContext(context); - credentials.setRoles(roles); - Utils.generateBearerToken(credentials); - Assert.fail(EXCEPTION_NOT_THROWN); - } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals(ErrorMessage.CredentialsStringInvalidJson.getMessage(), e.getMessage()); - } - } - - @Test - public void testGenerateBearerTokenWithToken() { - try { - Credentials credentials = new Credentials(); - credentials.setToken(token); - credentials.setContext(context); - credentials.setRoles(roles); - String bearerToken = Utils.generateBearerToken(credentials); - Assert.assertEquals(token, bearerToken); - } catch (SkyflowException e) { - Assert.fail(INVALID_EXCEPTION_THROWN); - } - } - @Test public void testConstructConnectionURL() { try { From 4c2b3a733bb74bd1dd31040fed8270439e3ce805 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Thu, 16 Jul 2026 16:20:40 +0530 Subject: [PATCH 08/28] SK-2967 update the internal release --- .github/workflows/internal-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/internal-release.yml b/.github/workflows/internal-release.yml index e8b8ee61..6881618b 100644 --- a/.github/workflows/internal-release.yml +++ b/.github/workflows/internal-release.yml @@ -16,6 +16,7 @@ jobs: server-id: central profile: jfrog tag: 'internal' + module: 'v2' secrets: server-username: ${{ secrets.ARTIFACTORY_USERNAME }} server-password: ${{ secrets.ARTIFACTORY_PASSWORD }} From 80e18fdbf5cb8ff2a984158ce86fe2bb5f700845 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Thu, 16 Jul 2026 16:32:36 +0530 Subject: [PATCH 09/28] SK-2967 update script version --- .github/workflows/shared-build-and-deploy.yml | 12 +++++++-- scripts/bump_version.sh | 27 ++++++++++--------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.github/workflows/shared-build-and-deploy.yml b/.github/workflows/shared-build-and-deploy.yml index 9d885190..cc771fe9 100644 --- a/.github/workflows/shared-build-and-deploy.yml +++ b/.github/workflows/shared-build-and-deploy.yml @@ -89,14 +89,22 @@ jobs: fallback: 1.0.0 - name: Bump Version + id: bump-version run: | chmod +x ./scripts/bump_version.sh if ${{ inputs.tag == 'internal' }}; then - ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "$(git rev-parse --short "$GITHUB_SHA")" + ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "$(git rev-parse --short "$GITHUB_SHA")" "${{ inputs.module }}" else ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "" "${{ inputs.module }}" fi + MODULE="${{ inputs.module }}" + if [ -n "$MODULE" ]; then + echo "pom_path=$MODULE/pom.xml" >> "$GITHUB_OUTPUT" + else + echo "pom_path=pom.xml" >> "$GITHUB_OUTPUT" + fi + - name: Commit changes run: | git config user.name ${{ github.actor }} @@ -106,7 +114,7 @@ jobs: git checkout ${{ env.branch_name }} fi - git add flowvault/pom.xml + git add ${{ steps.bump-version.outputs.pom_path }} if [[ "${{ inputs.tag }}" == "internal" ]]; then git commit -m "[AUTOMATED] Private Release ${{ steps.previoustag.outputs.tag }}-dev-$(git rev-parse --short $GITHUB_SHA)" git push origin ${{ github.ref_name }} -f diff --git a/scripts/bump_version.sh b/scripts/bump_version.sh index d729ea63..ccb538ba 100755 --- a/scripts/bump_version.sh +++ b/scripts/bump_version.sh @@ -1,7 +1,8 @@ # Input Arguments Version=$1 CommitHash=$2 -PomFile="$GITHUB_WORKSPACE/pom.xml" +Module=$3 +PomFile="$GITHUB_WORKSPACE/$Module/pom.xml" if [ -z "$Version" ]; then echo "Error: Version argument is required." @@ -14,27 +15,29 @@ if [ -z "$CommitHash" ]; then awk -v version="$Version" ' BEGIN { updated = 0 } + //,/<\/parent>/ { print; next } // && updated == 0 { sub(/.*<\/version>/, "" version "") updated = 1 } { print } - ' "$PomFile" > tempfile && cat tempfile > "$PomFile" && rm -f tempfile + ' "$PomFile" > tempfile && cat tempfile > "$PomFile" && rm -f tempfile echo "--------------------------" echo "Done. Main project version now at $Version" else echo "Bumping main project version to $Version-dev-$CommitHash" - awk -v version="$Version-dev.$CommitHash" ' - BEGIN { updated = 0 } - // && updated == 0 { - sub(/.*<\/version>/, "" version "") - updated = 1 - } - { print } - ' "$PomFile" > tempfile && cat tempfile > "$PomFile" && rm -f tempfile + awk -v version="$Version${CommitHash:+-dev.$CommitHash}" ' + BEGIN { updated = 0 } + //,/<\/parent>/ { print; next } + // && updated == 0 { + sub(/.*<\/version>/, "" version "") + updated = 1 + } + { print } + ' "$PomFile" > tempfile && cat tempfile > "$PomFile" && rm -f tempfile - echo "--------------------------" - echo "Done. Main project version now at $Version-dev.$CommitHash" +echo "--------------------------" +echo "Done. $Module module version now at $Version${CommitHash:+-dev.$CommitHash}" fi From a7cda5c5a6384469d4aa28100ea797d6acf5ebbb Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Thu, 16 Jul 2026 11:03:48 +0000 Subject: [PATCH 10/28] [AUTOMATED] Private Release 1.15.1-dev-f6a6992 --- v2/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/pom.xml b/v2/pom.xml index b35a9552..e988579b 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -11,7 +11,7 @@ skyflow-java - 2.1.1 + 1.15.1-dev.f6a6992 com.skyflow @@ -48,4 +48,4 @@
- \ No newline at end of file + From 678704e2155bd571cad115f29cc386d39ac38320 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Thu, 16 Jul 2026 19:14:26 +0530 Subject: [PATCH 11/28] SK-2967 update internal release workflow --- .github/workflows/internal-release.yml | 4 +-- .github/workflows/shared-build-and-deploy.yml | 28 +++++++------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/.github/workflows/internal-release.yml b/.github/workflows/internal-release.yml index 6881618b..70a33281 100644 --- a/.github/workflows/internal-release.yml +++ b/.github/workflows/internal-release.yml @@ -1,4 +1,4 @@ -name: Publish package to the JFROG Artifactory +name: Publish v2 module to the JFROG Artifactory on: push: tags-ignore: @@ -9,7 +9,7 @@ on: - release/* jobs: - build-and-deploy: + build-and-deploy-v2: uses: ./.github/workflows/shared-build-and-deploy.yml with: ref: ${{ github.ref_name }} diff --git a/.github/workflows/shared-build-and-deploy.yml b/.github/workflows/shared-build-and-deploy.yml index cc771fe9..77615306 100644 --- a/.github/workflows/shared-build-and-deploy.yml +++ b/.github/workflows/shared-build-and-deploy.yml @@ -59,19 +59,19 @@ jobs: fetch-depth: 0 - name: Set up maven or jfrog repository - uses: actions/setup-java@v4 + uses: actions/setup-java@v1 with: java-version: "11" distribution: "adopt" server-id: ${{ inputs.server-id }} - server-username: ${{ secrets.server-username }} - server-password: ${{ secrets.server-password }} + server-username: SERVER_USERNAME + server-password: SERVER_PASSWORD gpg-private-key: ${{ secrets.gpg-key }} # Value of the GPG private key to import - gpg-passphrase: ${{ secrets.gpg-passphrase }} # env variable for GPG private key passphrase - + gpg-passphrase: GPG_PASSPHRASE # env variable for GPG private key passphrase + - name: Resolve Branch for the Tagged Commit id: resolve-branch - if: ${{ inputs.tag == 'beta' || inputs.tag == 'public' }} + if: ${{ inputs.tag == 'beta' || inputs.tag == 'public' }} run: | TAG_COMMIT=$(git rev-list -n 1 ${{ github.ref_name }}) BRANCH_NAME=$(git branch -r --contains $TAG_COMMIT | grep -o 'origin/.*' | sed 's|origin/||' | head -n 1) @@ -89,7 +89,6 @@ jobs: fallback: 1.0.0 - name: Bump Version - id: bump-version run: | chmod +x ./scripts/bump_version.sh if ${{ inputs.tag == 'internal' }}; then @@ -98,13 +97,6 @@ jobs: ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "" "${{ inputs.module }}" fi - MODULE="${{ inputs.module }}" - if [ -n "$MODULE" ]; then - echo "pom_path=$MODULE/pom.xml" >> "$GITHUB_OUTPUT" - else - echo "pom_path=pom.xml" >> "$GITHUB_OUTPUT" - fi - - name: Commit changes run: | git config user.name ${{ github.actor }} @@ -114,7 +106,7 @@ jobs: git checkout ${{ env.branch_name }} fi - git add ${{ steps.bump-version.outputs.pom_path }} + git add ${{ inputs.module }}/pom.xml if [[ "${{ inputs.tag }}" == "internal" ]]; then git commit -m "[AUTOMATED] Private Release ${{ steps.previoustag.outputs.tag }}-dev-$(git rev-parse --short $GITHUB_SHA)" git push origin ${{ github.ref_name }} -f @@ -142,12 +134,12 @@ jobs: - name: Publish package run: | if [[ "${{ inputs.tag }}" == "internal" ]]; then - mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P jfrog -DskipTests + mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P jfrog -DskipTests elif [[ "${{ inputs.tag }}" == "beta" || "${{ inputs.tag }}" == "public" ]]; then - mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P ${{ inputs.profile }} -DskipTests + mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P ${{ inputs.profile }} fi env: SERVER_USERNAME: ${{ secrets.server-username }} SERVER_PASSWORD: ${{ secrets.server-password }} - GPG_PASSPHRASE: ${{ secrets.gpg-passphrase }} + GPG_PASSPHRASE: ${{ secrets.gpg-passphrase }} \ No newline at end of file From e14faed5e37c7112ece55c73ec25564544351094 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Thu, 16 Jul 2026 13:47:20 +0000 Subject: [PATCH 12/28] [AUTOMATED] Private Release 1.15.1-dev-807824c --- v2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/pom.xml b/v2/pom.xml index e988579b..01370ded 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -11,7 +11,7 @@ skyflow-java - 1.15.1-dev.f6a6992 + 1.15.1-dev.807824c com.skyflow From ca1cfb4781d5fcbe62f016367ab40b4eb7adf52f Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 17:49:42 +0530 Subject: [PATCH 13/28] SK-2967 add interfaces --- .../main/java/com/skyflow/BaseSkyflow.java | 2 +- .../main/java/com/skyflow/logs/ErrorLogs.java | 1 + .../java/com/skyflow/logs/WarningLogs.java | 6 +- .../serviceaccount/util/BearerToken.java | 4 +- .../main/java/com/skyflow/utils/Utils.java | 100 ++- .../utils/validations/Validations.java | 89 ++- .../vault/controller/VaultController.java | 58 +- .../vault/data/DeleteTokensRequest.java | 34 + .../vault/data/DeleteTokensResponse.java | 22 + .../com/skyflow/vault/data/TokenizeData.java | 36 + .../skyflow/vault/data/TokenizeRecord.java | 44 ++ .../skyflow/vault/data/TokenizeRequest.java | 30 + .../skyflow/vault/data/TokenizeResponse.java | 22 + .../test/java/com/skyflow/SkyflowTests.java | 168 ++++ .../java/com/skyflow/VaultClientTests.java | 130 ++++ .../com/skyflow/config/VaultConfigTests.java | 94 +++ .../java/com/skyflow/utils/UtilsTests.java | 568 ++++++++++++++ .../utils/validations/ValidationsTests.java | 732 ++++++++++++++++++ .../controller/VaultControllerTests.java | 445 +++++++++++ .../vault/tokens/TokenizeResponse.java | 8 +- 20 files changed, 2571 insertions(+), 22 deletions(-) create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenizeData.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenizeRecord.java create mode 100644 flowvault/src/test/java/com/skyflow/SkyflowTests.java create mode 100644 flowvault/src/test/java/com/skyflow/VaultClientTests.java create mode 100644 flowvault/src/test/java/com/skyflow/config/VaultConfigTests.java create mode 100644 flowvault/src/test/java/com/skyflow/utils/UtilsTests.java create mode 100644 flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java create mode 100644 flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java index 2daff37b..7e7554ff 100644 --- a/common/src/main/java/com/skyflow/BaseSkyflow.java +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -16,7 +16,7 @@ import java.util.Map; -abstract class BaseSkyflow implements ISkyflow { +abstract class BaseSkyflow implements ISkyflow { protected final BaseSkyflowClientBuilder builder; protected BaseSkyflow(BaseSkyflowClientBuilder builder) { diff --git a/common/src/main/java/com/skyflow/logs/ErrorLogs.java b/common/src/main/java/com/skyflow/logs/ErrorLogs.java index 0028a5c6..b77eee2c 100644 --- a/common/src/main/java/com/skyflow/logs/ErrorLogs.java +++ b/common/src/main/java/com/skyflow/logs/ErrorLogs.java @@ -127,6 +127,7 @@ public enum ErrorLogs { EMPTY_DELETE_TOKENS_DATA("Invalid %s1 request. Delete tokens data can not be empty."), EMPTY_OR_NULL_TOKEN_IN_DELETE_TOKENS_DATA("Invalid %s1 request. Token can not be null or empty in delete tokens data at index %s2."), DELETE_TOKENS_SIZE_EXCEED("Maximum number of tokens exceeded. The limit is 10000."), + DELETE_TOKENS_REQUEST_REJECTED("DeleteTokens request resulted in failure."), // invoke connection interface INVOKE_CONNECTION_INVALID_CONNECTION_URL("Invalid %s1 request. Connection URL is not a valid URL."), diff --git a/common/src/main/java/com/skyflow/logs/WarningLogs.java b/common/src/main/java/com/skyflow/logs/WarningLogs.java index 5f80a728..1eb1bcd8 100644 --- a/common/src/main/java/com/skyflow/logs/WarningLogs.java +++ b/common/src/main/java/com/skyflow/logs/WarningLogs.java @@ -4,7 +4,11 @@ public enum WarningLogs { INVALID_BATCH_SIZE_PROVIDED("Invalid value for batch size provided, switching to default value."), INVALID_CONCURRENCY_LIMIT_PROVIDED("Invalid value for concurrency limit provided, switching to default value."), BATCH_SIZE_EXCEEDS_MAX_LIMIT("Provided batch size exceeds the maximum limit, switching to max limit."), - CONCURRENCY_EXCEEDS_MAX_LIMIT("Provided concurrency limit exceeds the maximum limit, switching to max limit.") + CONCURRENCY_EXCEEDS_MAX_LIMIT("Provided concurrency limit exceeds the maximum limit, switching to max limit."), + EMPTY_DELETE_TOKENS_RESPONSE("DeleteTokens response did not include any token results."), + INCOMPLETE_DELETE_TOKENS_RESPONSE("DeleteTokens response did not account for all requested tokens."), + EMPTY_TOKENIZE_RESPONSE("Tokenize response did not include any record results."), + INCOMPLETE_TOKENIZE_RESPONSE("Tokenize response did not account for all requested records.") ; private final String log; diff --git a/common/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java b/common/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java index 317847e5..60c07f6d 100644 --- a/common/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java +++ b/common/src/main/java/com/skyflow/serviceaccount/util/BearerToken.java @@ -65,7 +65,7 @@ private static V1GetAuthTokenResponse generateBearerTokenFromCredentials( } finally { try { reader.close(); } catch (IOException ignored) {} } - } catch (JsonSyntaxException e) { + } catch (JsonSyntaxException | IllegalStateException e) { LogUtil.printErrorLog(ErrorLogs.INVALID_CREDENTIALS_FILE_FORMAT.getLog()); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseUtils.parameterizedString( ErrorMessage.FileInvalidJson.getMessage(), credentialsFile.getPath())); @@ -87,7 +87,7 @@ private static V1GetAuthTokenResponse generateBearerTokenFromCredentialString( } JsonObject serviceAccountCredentials = JsonParser.parseString(credentials).getAsJsonObject(); return getBearerTokenFromCredentials(serviceAccountCredentials, context, roles); - } catch (JsonSyntaxException e) { + } catch (JsonSyntaxException | IllegalStateException e) { LogUtil.printErrorLog(ErrorLogs.INVALID_CREDENTIALS_STRING_FORMAT.getLog()); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.CredentialsStringInvalidJson.getMessage()); diff --git a/flowvault/src/main/java/com/skyflow/utils/Utils.java b/flowvault/src/main/java/com/skyflow/utils/Utils.java index 670aa05b..cb69453f 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Utils.java +++ b/flowvault/src/main/java/com/skyflow/utils/Utils.java @@ -14,6 +14,7 @@ import com.skyflow.generated.rest.types.*; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; +import com.skyflow.logs.WarningLogs; import com.skyflow.serviceaccount.util.BearerToken; import com.skyflow.serviceaccount.util.Token; import com.skyflow.utils.logger.LogUtil; @@ -165,7 +166,7 @@ public static InsertResponse buildInsertResponse(V1InsertResponse res) { ArrayList> insertedFields = new ArrayList<>(); ArrayList> errors = new ArrayList<>(); - if (res.getRecords().isPresent()) { + if (res != null && res.getRecords().isPresent()) { for (V1RecordResponseObject record : res.getRecords().get()) { if (record.getError().isPresent()) { HashMap errorRecord = new HashMap<>(); @@ -215,7 +216,7 @@ public static DetokenizeResponse buildDetokenizeResponse(V1FlowDetokenizeRespons ArrayList detokenizedFields = new ArrayList<>(); ArrayList errors = new ArrayList<>(); - if (res.getResponse().isPresent()) { + if (res != null && res.getResponse().isPresent()) { for (V1FlowDetokenizeResponseObject record : res.getResponse().get()) { String token = record.getToken().orElse(null); String tokenGroupName = record.getTokenGroupName().orElse(null); @@ -230,4 +231,99 @@ public static DetokenizeResponse buildDetokenizeResponse(V1FlowDetokenizeRespons } return new DetokenizeResponse(detokenizedFields, errors); } + + public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest getDeleteTokensRequestBody(DeleteTokensRequest request, String vaultid) { + return com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest.builder() + .vaultId(vaultid) + .tokens(request.getTokens()) + .build(); + } + private static String extractRequestId(Map> headers) { + if (headers == null) return null; + List ids = headers.get(BaseConstants.REQUEST_ID_HEADER_KEY); + return (ids == null || ids.isEmpty()) ? null : ids.get(0); + } + + public static DeleteTokensResponse buildDeleteTokensResponse(V1FlowDeleteTokenResponse res, Map> headers, int requestedTokenCount) { + ArrayList deletedTokens = new ArrayList<>(); + ArrayList> errors = new ArrayList<>(); + String requestId = extractRequestId(headers); + if (res != null && res.getTokens().isPresent()) { + for (V1DeleteTokenResponseObject record : res.getTokens().get()) { + if (record.getError().isPresent()) { + HashMap errorRecord = new HashMap<>(); + errorRecord.put("error", record.getError().get()); + record.getHttpCode().ifPresent(httpCode -> errorRecord.put("httpCode", httpCode)); + errorRecord.put("requestId", requestId); + errors.add(errorRecord); + } else { + record.getValue().ifPresent(deletedTokens::add); + } + } + if (deletedTokens.size() + errors.size() != requestedTokenCount) { + LogUtil.printWarningLog(WarningLogs.INCOMPLETE_DELETE_TOKENS_RESPONSE.getLog()); + } + } else { + LogUtil.printWarningLog(WarningLogs.EMPTY_DELETE_TOKENS_RESPONSE.getLog()); + } + return new DeleteTokensResponse(deletedTokens, errors); + } + + public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest getTokenizeRequestBody(TokenizeRequest request, String vaultid) { + List dataList = new ArrayList<>(); + for (TokenizeRecord record : request.getData()) { + V1FlowTokenizeRequestObject obj = V1FlowTokenizeRequestObject.builder() + .value(record.getValue()) + .tokenGroupNames(record.getTokenGroupNames()) + .build(); + dataList.add(obj); + } + return com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest.builder() + .vaultId(vaultid) + .data(dataList) + .build(); + } + + public static TokenizeResponse buildTokenizeResponse(V1FlowTokenizeResponse res, Map> headers, int requestedRecordCount) { + List tokenizedData = new ArrayList<>(); + ArrayList> errors = new ArrayList<>(); + String requestId = extractRequestId(headers); + if (res != null && res.getResponse().isPresent()) { + List records = res.getResponse().get(); + int indexNumber = 0; + for (V1FlowTokenizeResponseObject record : records) { + Object value = record.getValue().orElse(null); + TokenizeData tokenizeData = new TokenizeData(value, indexNumber); + boolean hasAnySuccess = false; + if (record.getTokens().isPresent()) { + for (FlowTokenizeResponseObjectToken tokenObj : record.getTokens().get()) { + if (tokenObj.getError().isPresent()) { + HashMap errorRecord = new HashMap<>(); + errorRecord.put("error", tokenObj.getError().get()); + tokenObj.getHttpCode().ifPresent(httpCode -> errorRecord.put("httpCode", httpCode)); + tokenObj.getTokenGroupName().ifPresent(name -> errorRecord.put("tokenGroupName", name)); + errorRecord.put("index", indexNumber); + errorRecord.put("requestId", requestId); + errors.add(errorRecord); + } else if (tokenObj.getTokenGroupName().isPresent() && tokenObj.getToken().isPresent()) { + tokenizeData.addToken(tokenObj.getTokenGroupName().get(), tokenObj.getToken().get()); + hasAnySuccess = true; + } + } + } + if (hasAnySuccess) { + tokenizedData.add(tokenizeData); + } + indexNumber++; + } + if (indexNumber != requestedRecordCount) { + LogUtil.printWarningLog(WarningLogs.INCOMPLETE_TOKENIZE_RESPONSE.getLog()); + } + } else { + LogUtil.printWarningLog(WarningLogs.EMPTY_TOKENIZE_RESPONSE.getLog()); + } + TokenizeResponse tokenizeResponse = new TokenizeResponse(errors); + tokenizeResponse.setTokenizedData(tokenizedData); + return tokenizeResponse; + } } diff --git a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java index c94fe05b..98dfdf64 100644 --- a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java @@ -165,10 +165,7 @@ public static void validateInsertRequest(InsertRequest insertRequest) throws Sky )); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRecords.getMessage()); } -// else if (records.size() > 10000) { -// LogUtil.printErrorLog(ErrorLogs.RECORD_SIZE_EXCEED.getLog()); -// throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.RecordSizeExceedError.getMessage()); -// } + for (InsertRecord record : records) { if(record == null){ LogUtil.printErrorLog(Utils.parameterizedString( @@ -273,13 +270,10 @@ public static void validateDetokenizeRequest(DetokenizeRequest request) throws S )); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDetokenizeData.getMessage()); } -// if (tokens.size() > 10000) { -// LogUtil.printErrorLog(ErrorLogs.TOKENS_SIZE_EXCEED.getLog()); -// throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TokensSizeExceedError.getMessage()); -// } + for (int index = 0; index < tokens.size(); index++) { DetokenizeData token = tokens.get(index); - if (token != null && token.getToken().isEmpty() && token.getToken().trim().isEmpty()) { + if (token == null || token.getToken() == null || token.getToken().trim().isEmpty()) { LogUtil.printErrorLog(Utils.parameterizedString( ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_DETOKENIZE_DATA.getLog(), InterfaceName.DETOKENIZE.getName(), @@ -307,7 +301,84 @@ public static void validateDetokenizeRequest(DetokenizeRequest request) throws S } } } + } + public static void validateDeleteTokensRequest(DeleteTokensRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.DELETE_TOKENS_REQUEST_NULL.getLog(), InterfaceName.DELETE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.DeleteTokensRequestNull.getMessage()); + } + List tokens = request.getTokens(); + if (tokens == null || tokens.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_DELETE_TOKENS_DATA.getLog(), InterfaceName.DELETE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDeleteTokensData.getMessage()); + } + + for (int index = 0; index < tokens.size(); index++) { + String token = tokens.get(index); + if (token == null || token.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_DELETE_TOKENS_DATA.getLog(), + InterfaceName.DELETE.getName(), + String.valueOf(index))); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenInDeleteTokensData.getMessage()); + } + } + } + + public static void validateTokenizeRequest(TokenizeRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TOKENIZE_REQUEST_NULL.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TokenizeRequestNull.getMessage()); + } + ArrayList data = request.getData(); + if (data == null || data.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_TOKENIZE_DATA.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenizeData.getMessage()); + } + for (int index = 0; index < data.size(); index++) { + TokenizeRecord record = data.get(index); + if (record == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TOKENIZE_RECORD_NULL.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TokenizeRecordNull.getMessage()); + } + Object value = record.getValue(); + boolean isInvalidValue = value == null || (value instanceof String && ((String) value).trim().isEmpty()); + if (isInvalidValue) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_VALUE_IN_TOKENIZE_RECORD.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyValueInTokenizeRecord.getMessage()); + } + List tokenGroupNames = record.getTokenGroupNames(); + if (tokenGroupNames == null || tokenGroupNames.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_TOKEN_GROUP_NAMES_IN_TOKENIZE_RECORD.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenGroupNamesInTokenizeRecord.getMessage()); + } + for (int groupIndex = 0; groupIndex < tokenGroupNames.size(); groupIndex++) { + String groupName = tokenGroupNames.get(groupIndex); + if (groupName == null || groupName.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_TOKEN_GROUP_NAME_IN_TOKENIZE_RECORD.getLog(), + InterfaceName.TOKENIZE.getName(), + String.valueOf(groupIndex))); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenGroupNameInTokenizeRecord.getMessage()); + } + } + } + } } diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java index 24ba2b3f..28c29839 100644 --- a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -8,8 +8,12 @@ import com.skyflow.config.VaultConfig; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; +import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; +import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; import com.skyflow.generated.rest.types.V1InsertResponse; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; @@ -49,6 +53,9 @@ public InsertResponse insert(InsertRequest request) throws SkyflowException { String bodyString = gson.toJson(e.body()); LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); } } @@ -68,17 +75,58 @@ public DetokenizeResponse detokenize(DetokenizeRequest request) throws SkyflowEx String bodyString = gson.toJson(e.body()); LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); } } - public TokenizeResponse tokenize(TokenizeRequest request){ - LogUtil.printInfoLog(InfoLogs.TOKENIZE_TRIGGERED.getLog()); + public TokenizeResponse tokenize(TokenizeRequest request) throws SkyflowException { try { + LogUtil.printInfoLog(InfoLogs.TOKENIZE_TRIGGERED.getLog()); + LogUtil.printInfoLog(InfoLogs.VALIDATING_TOKENIZE_REQUEST.getLog()); + Validations.validateTokenizeRequest(request); + setBearerToken(); - } catch (Exception e) { - throw new RuntimeException(e); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest requestTokenize = getTokenizeRequestBody(request, this.getVaultConfig().getVaultId()); + ApiClientHttpResponse response = this.getRecordsApi().withRawResponse().tokenize(requestTokenize, buildRequestOptions()); + LogUtil.printInfoLog(InfoLogs.TOKENIZE_REQUEST_RESOLVED.getLog()); + + TokenizeResponse tokenizeResponse = buildTokenizeResponse(response.body(), response.headers(), request.getData().size()); + LogUtil.printInfoLog(InfoLogs.TOKENIZE_SUCCESS.getLog()); + return tokenizeResponse; + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } + } + + public DeleteTokensResponse deleteTokens(DeleteTokensRequest request) throws SkyflowException { + try { + LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_TRIGGERED.getLog()); + LogUtil.printInfoLog(InfoLogs.VALIDATE_DELETE_TOKENS_REQUEST.getLog()); + Validations.validateDeleteTokensRequest(request); + setBearerToken(); + + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest requestDeleteTokens = getDeleteTokensRequestBody(request, this.getVaultConfig().getVaultId()); + ApiClientHttpResponse response = this.getRecordsApi().withRawResponse().deletetoken(requestDeleteTokens, buildRequestOptions()); + LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_REQUEST_RESOLVED.getLog()); + + DeleteTokensResponse deleteTokensResponse = buildDeleteTokensResponse(response.body(), response.headers(), request.getTokens().size()); + LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_SUCCESS.getLog()); + return deleteTokensResponse; + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.DELETE_TOKENS_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.DELETE_TOKENS_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); } - return null; } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensRequest.java new file mode 100644 index 00000000..ea8e9a7a --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensRequest.java @@ -0,0 +1,34 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class DeleteTokensRequest { + private final DeleteTokensRequestBuilder builder; + + private DeleteTokensRequest(DeleteTokensRequestBuilder builder) { + this.builder = builder; + } + + public static DeleteTokensRequestBuilder builder() { + return new DeleteTokensRequestBuilder(); + } + + public List getTokens() { + return this.builder.tokens; + } + + public static final class DeleteTokensRequestBuilder { + private List tokens; + + private DeleteTokensRequestBuilder() {} + + public DeleteTokensRequestBuilder tokens(List tokens) { + this.tokens = tokens; + return this; + } + + public DeleteTokensRequest build() { + return new DeleteTokensRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensResponse.java new file mode 100644 index 00000000..7f621d8d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensResponse.java @@ -0,0 +1,22 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class DeleteTokensResponse { + private final List tokens; + private final ArrayList> errors; + + public DeleteTokensResponse(List tokens, ArrayList> errors) { + this.tokens = tokens; + this.errors = errors; + } + + public List getTokens() { + return tokens; + } + public ArrayList> getErrors(){ + return this.errors; + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeData.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeData.java new file mode 100644 index 00000000..6f04ed8d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeData.java @@ -0,0 +1,36 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class TokenizeData { + private Object value; + private Map tokens; + private int index; + + public TokenizeData(Object value, int index){ + this.value = value; + this.tokens = new LinkedHashMap<>(); + this.index = index; + } + public void addToken(String tokenGroupName, String token) { + this.tokens.put(tokenGroupName, token); + } + + public Object getValue() { + return value; + } + + public Map getTokens() { + return tokens; + } + + @Override + public String toString() { + Gson gson = new GsonBuilder().create(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRecord.java new file mode 100644 index 00000000..faa676df --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRecord.java @@ -0,0 +1,44 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class TokenizeRecord { + private final TokenizeRecordBuilder builder; + + private TokenizeRecord(TokenizeRecordBuilder builder) { + this.builder = builder; + } + + public static TokenizeRecordBuilder builder() { + return new TokenizeRecordBuilder(); + } + + public Object getValue() { + return this.builder.value; + } + + public List getTokenGroupNames() { + return this.builder.tokenGroupNames; + } + + public static final class TokenizeRecordBuilder { + private Object value; + private List tokenGroupNames; + + private TokenizeRecordBuilder() {} + + public TokenizeRecordBuilder value(Object value) { + this.value = value; + return this; + } + + public TokenizeRecordBuilder tokenGroupNames(List tokenGroupNames) { + this.tokenGroupNames = tokenGroupNames; + return this; + } + + public TokenizeRecord build() { + return new TokenizeRecord(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java index f6b6cf99..a6ef8072 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeRequest.java @@ -1,4 +1,34 @@ package com.skyflow.vault.data; +import java.util.ArrayList; + public class TokenizeRequest { + private final TokenizeRequestBuilder builder; + + private TokenizeRequest(TokenizeRequestBuilder builder) { + this.builder = builder; + } + + public static TokenizeRequestBuilder builder() { + return new TokenizeRequestBuilder(); + } + + public ArrayList getData() { + return this.builder.data; + } + + public static final class TokenizeRequestBuilder { + private ArrayList data; + + private TokenizeRequestBuilder() {} + + public TokenizeRequestBuilder data(ArrayList data) { + this.data = data; + return this; + } + + public TokenizeRequest build() { + return new TokenizeRequest(this); + } + } } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java index 403ad53c..a4b47351 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeResponse.java @@ -1,4 +1,26 @@ package com.skyflow.vault.data; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + public class TokenizeResponse { + private List tokenizedData; + private final ArrayList> errors; + + public TokenizeResponse(ArrayList> errors) { + this.errors = errors; + } + public TokenizeResponse(){ + this.errors = new ArrayList<>(); + } + public List getTokenizedData(){ + return this.tokenizedData; + } + public void setTokenizedData(List tokenizedData) { + this.tokenizedData = tokenizedData; + } + public ArrayList> getErrors(){ + return this.errors; + } } diff --git a/flowvault/src/test/java/com/skyflow/SkyflowTests.java b/flowvault/src/test/java/com/skyflow/SkyflowTests.java new file mode 100644 index 00000000..fc215e2b --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/SkyflowTests.java @@ -0,0 +1,168 @@ +package com.skyflow; + +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.Env; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.controller.VaultController; +import org.junit.Assert; +import org.junit.Test; + +public class SkyflowTests { + private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; + + private static VaultConfig buildConfig(String vaultId, String clusterId) { + VaultConfig config = new VaultConfig(); + config.setVaultId(vaultId); + config.setClusterId(clusterId); + config.setEnv(Env.DEV); + return config; + } + + // ── addVaultConfig ──────────────────────────────────────────────────────── + + @Test + public void testAddVaultConfig_success() throws SkyflowException { + Skyflow client = Skyflow.builder().addVaultConfig(buildConfig("vault1", "cluster1")).build(); + Assert.assertEquals("vault1", client.getVaultConfig("vault1").getVaultId()); + } + + @Test + public void testAddVaultConfig_duplicateVaultIdThrows() throws SkyflowException { + Skyflow.SkyflowClientBuilder builder = Skyflow.builder().addVaultConfig(buildConfig("vault1", "cluster1")); + try { + builder.addVaultConfig(buildConfig("vault1", "cluster2")); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testAddVaultConfig_invalidConfigThrows() { + VaultConfig config = new VaultConfig(); + // no vaultId set + try { + Skyflow.builder().addVaultConfig(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── updateVaultConfig ───────────────────────────────────────────────────── + + @Test + public void testUpdateVaultConfig_success() throws SkyflowException { + Skyflow client = Skyflow.builder().addVaultConfig(buildConfig("vault1", "cluster1")).build(); + + VaultConfig update = new VaultConfig(); + update.setVaultId("vault1"); + update.setClusterId("cluster2"); + update.setEnv(Env.PROD); + client.updateVaultConfig(update); + + Assert.assertEquals("cluster2", client.getVaultConfig("vault1").getClusterId()); + Assert.assertEquals(Env.PROD, client.getVaultConfig("vault1").getEnv()); + } + + @Test + public void testUpdateVaultConfig_nonExistentVaultIdThrows() { + try { + Skyflow.builder().updateVaultConfig(buildConfig("vault-unknown", "cluster1")); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── removeVaultConfig ───────────────────────────────────────────────────── + + @Test + public void testRemoveVaultConfig_success() throws SkyflowException { + Skyflow client = Skyflow.builder().addVaultConfig(buildConfig("vault1", "cluster1")).build(); + client.removeVaultConfig("vault1"); + Assert.assertNull(client.getVaultConfig("vault1")); + } + + @Test + public void testRemoveVaultConfig_nonExistentVaultIdThrows() { + try { + Skyflow.builder().removeVaultConfig("vault-unknown"); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── addSkyflowCredentials ───────────────────────────────────────────────── + + @Test + public void testAddSkyflowCredentials_success() throws SkyflowException { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + Skyflow client = Skyflow.builder() + .addVaultConfig(buildConfig("vault1", "cluster1")) + .addSkyflowCredentials(credentials) + .build(); + Assert.assertNotNull(client); + } + + @Test + public void testAddSkyflowCredentials_invalidCredentialsThrows() { + Credentials credentials = new Credentials(); + credentials.setApiKey("not-a-valid-api-key"); + try { + Skyflow.builder().addSkyflowCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── setLogLevel / getLogLevel ───────────────────────────────────────────── + + @Test + public void testSetLogLevel_updatesLogLevel() throws SkyflowException { + Skyflow client = Skyflow.builder() + .addVaultConfig(buildConfig("vault1", "cluster1")) + .setLogLevel(LogLevel.DEBUG) + .build(); + Assert.assertEquals(LogLevel.DEBUG, client.getLogLevel()); + } + + @Test + public void testGetLogLevel_defaultsToError() throws SkyflowException { + Skyflow client = Skyflow.builder().addVaultConfig(buildConfig("vault1", "cluster1")).build(); + Assert.assertEquals(LogLevel.ERROR, client.getLogLevel()); + } + + // ── vault() ─────────────────────────────────────────────────────────────── + + @Test + public void testVault_returnsVaultControllerWhenConfigured() throws SkyflowException { + Skyflow client = Skyflow.builder().addVaultConfig(buildConfig("vault1", "cluster1")).build(); + VaultController controller = client.vault(); + Assert.assertNotNull(controller); + } + + @Test + public void testVault_throwsWhenNoConfigExists() { + try { + Skyflow.builder().build().vault(); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── getVaultConfig ──────────────────────────────────────────────────────── + + @Test + public void testGetVaultConfig_returnsNullForUnknownVaultId() throws SkyflowException { + Skyflow client = Skyflow.builder().addVaultConfig(buildConfig("vault1", "cluster1")).build(); + Assert.assertNull(client.getVaultConfig("vault-unknown")); + } +} diff --git a/flowvault/src/test/java/com/skyflow/VaultClientTests.java b/flowvault/src/test/java/com/skyflow/VaultClientTests.java new file mode 100644 index 00000000..24e741b5 --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/VaultClientTests.java @@ -0,0 +1,130 @@ +package com.skyflow; + +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.Env; +import com.skyflow.errors.SkyflowException; +import org.junit.Assert; +import org.junit.Test; + +public class VaultClientTests { + + private static VaultConfig buildConfig(String vaultId, String clusterId, Credentials credentials) { + VaultConfig config = new VaultConfig(); + config.setVaultId(vaultId); + config.setClusterId(clusterId); + config.setEnv(Env.DEV); + if (credentials != null) { + config.setCredentials(credentials); + } + return config; + } + + // ── updateVaultURL priority order ──────────────────────────────────────── + + @Test + public void testUpdateVaultURL_usesExplicitVaultURLOverClusterId() throws SkyflowException { + VaultConfig config = buildConfig("vault1", "cluster1", null); + config.setVaultURL("https://custom.example.com"); + + VaultClient client = new VaultClient(config, null); + + Assert.assertEquals("https://custom.example.com", client.currentVaultURL); + } + + @Test + public void testUpdateVaultURL_constructsFromClusterIdWhenNoVaultURL() throws SkyflowException { + VaultConfig config = buildConfig("vault1", "cluster1", null); + + VaultClient client = new VaultClient(config, null); + + Assert.assertEquals("https://cluster1.skyvault.skyflowapis.dev", client.currentVaultURL); + } + + // ── setBearerToken ──────────────────────────────────────────────────────── + + @Test + public void testSetBearerToken_usesApiKeyDirectly() throws SkyflowException { + Credentials creds = new Credentials(); + creds.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + VaultConfig config = buildConfig("vault1", "cluster1", creds); + + VaultClient client = new VaultClient(config, null); + client.setBearerToken(); + + Assert.assertEquals("sky-ab123-abcd1234cdef1234abcd4321cdef4321", client.token); + } + + @Test + public void testSetBearerToken_reusesNonExpiredToken() throws SkyflowException { + Credentials creds = new Credentials(); + creds.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); + VaultConfig config = buildConfig("vault1", "cluster1", creds); + + VaultClient client = new VaultClient(config, null); + client.setBearerToken(); + String firstToken = client.token; + client.setBearerToken(); + + Assert.assertEquals(firstToken, client.token); + } + + @Test + public void testSetBearerToken_invalidCredentialsThrows() { + Credentials creds = new Credentials(); + creds.setApiKey("not-a-valid-api-key"); + VaultConfig config = buildConfig("vault1", "cluster1", creds); + + try { + VaultClient client = new VaultClient(config, null); + client.setBearerToken(); + Assert.fail("Should have thrown an exception"); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── getRecordsApi ───────────────────────────────────────────────────────── + + @Test + public void testGetRecordsApi_availableAfterSetBearerToken() throws SkyflowException { + Credentials creds = new Credentials(); + creds.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + VaultConfig config = buildConfig("vault1", "cluster1", creds); + + VaultClient client = new VaultClient(config, null); + client.setBearerToken(); + + Assert.assertNotNull(client.getRecordsApi()); + } + + // ── setCommonCredentials ────────────────────────────────────────────────── + + @Test + public void testSetCommonCredentials_vaultSpecificCredentialsTakePriority() throws SkyflowException { + Credentials vaultCreds = new Credentials(); + vaultCreds.setToken("vault-specific-token"); + VaultConfig config = buildConfig("vault1", "cluster1", vaultCreds); + + VaultClient client = new VaultClient(config, null); + Credentials commonCreds = new Credentials(); + commonCreds.setToken("common-token"); + client.setCommonCredentials(commonCreds); + client.setBearerToken(); + + Assert.assertEquals("vault-specific-token", client.token); + } + + @Test + public void testSetCommonCredentials_usedWhenNoVaultSpecificCredentials() throws SkyflowException { + VaultConfig config = buildConfig("vault1", "cluster1", null); + + VaultClient client = new VaultClient(config, null); + Credentials commonCreds = new Credentials(); + commonCreds.setToken("common-token"); + client.setCommonCredentials(commonCreds); + client.setBearerToken(); + + Assert.assertEquals("common-token", client.token); + } +} diff --git a/flowvault/src/test/java/com/skyflow/config/VaultConfigTests.java b/flowvault/src/test/java/com/skyflow/config/VaultConfigTests.java new file mode 100644 index 00000000..a1c82af5 --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/config/VaultConfigTests.java @@ -0,0 +1,94 @@ +package com.skyflow.config; + +import com.skyflow.enums.Env; +import org.junit.Assert; +import org.junit.Test; + +public class VaultConfigTests { + + @Test + public void testDefaultEnvIsProd() { + VaultConfig config = new VaultConfig(); + Assert.assertEquals(Env.PROD, config.getEnv()); + } + + @Test + public void testSettingNullEnvFallsBackToProd() { + VaultConfig config = new VaultConfig(); + config.setEnv(null); + Assert.assertEquals(Env.PROD, config.getEnv()); + } + + @Test + public void testVaultIdGetterSetter() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + Assert.assertEquals("vault123", config.getVaultId()); + } + + @Test + public void testClusterIdGetterSetter() { + VaultConfig config = new VaultConfig(); + config.setClusterId("cluster123"); + Assert.assertEquals("cluster123", config.getClusterId()); + } + + @Test + public void testEnvGetterSetter() { + VaultConfig config = new VaultConfig(); + config.setEnv(Env.SANDBOX); + Assert.assertEquals(Env.SANDBOX, config.getEnv()); + } + + @Test + public void testCredentialsGetterSetter() { + VaultConfig config = new VaultConfig(); + Credentials credentials = new Credentials(); + credentials.setToken("token1"); + config.setCredentials(credentials); + Assert.assertEquals(credentials, config.getCredentials()); + } + + @Test + public void testVaultURLDefaultsToNull() { + VaultConfig config = new VaultConfig(); + Assert.assertNull(config.getVaultURL()); + } + + @Test + public void testVaultURLGetterSetter() { + VaultConfig config = new VaultConfig(); + config.setVaultURL("https://myvault.example.com"); + Assert.assertEquals("https://myvault.example.com", config.getVaultURL()); + } + + @Test + public void testClone_copiesFieldsAndDeepCopiesCredentials() throws CloneNotSupportedException { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId("cluster123"); + config.setEnv(Env.DEV); + Credentials credentials = new Credentials(); + credentials.setToken("token1"); + config.setCredentials(credentials); + + VaultConfig cloned = (VaultConfig) config.clone(); + + Assert.assertEquals(config.getVaultId(), cloned.getVaultId()); + Assert.assertEquals(config.getClusterId(), cloned.getClusterId()); + Assert.assertEquals(config.getEnv(), cloned.getEnv()); + Assert.assertNotSame(config.getCredentials(), cloned.getCredentials()); + Assert.assertEquals(config.getCredentials().getToken(), cloned.getCredentials().getToken()); + } + + @Test + public void testClone_withNullCredentials() throws CloneNotSupportedException { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId("cluster123"); + + VaultConfig cloned = (VaultConfig) config.clone(); + + Assert.assertNull(cloned.getCredentials()); + } +} diff --git a/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java new file mode 100644 index 00000000..425f461a --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java @@ -0,0 +1,568 @@ +package com.skyflow.utils; + +import com.google.gson.JsonObject; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.Env; +import com.skyflow.enums.UpsertType; +import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest; +import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; +import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest; +import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; +import com.skyflow.generated.rest.types.FlowEnumUpdateType; +import com.skyflow.generated.rest.types.FlowTokenizeResponseObjectToken; +import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; +import com.skyflow.generated.rest.types.V1FlowDetokenizeResponse; +import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; +import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; +import com.skyflow.generated.rest.types.V1FlowTokenizeResponseObject; +import com.skyflow.generated.rest.types.V1InsertResponse; +import com.skyflow.generated.rest.types.V1RecordResponseObject; +import com.skyflow.vault.data.DeleteTokensRequest; +import com.skyflow.vault.data.DeleteTokensResponse; +import com.skyflow.vault.data.DetokenizeData; +import com.skyflow.vault.data.DetokenizeRecordResponse; +import com.skyflow.vault.data.DetokenizeRequest; +import com.skyflow.vault.data.DetokenizeResponse; +import com.skyflow.vault.data.InsertRecord; +import com.skyflow.vault.data.InsertRequest; +import com.skyflow.vault.data.InsertResponse; +import com.skyflow.vault.data.TokenGroupRedactions; +import com.skyflow.vault.data.TokenizeData; +import com.skyflow.vault.data.TokenizeRecord; +import com.skyflow.vault.data.TokenizeRequest; +import com.skyflow.vault.data.TokenizeResponse; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class UtilsTests { + + // ── getVaultURL ─────────────────────────────────────────────────────────── + + @Test + public void testGetVaultURL_prodEnv() { + String url = Utils.getVaultURL("cluster1", Env.PROD); + Assert.assertEquals("https://cluster1.skyvault.skyflowapis.com", url); + } + + @Test + public void testGetVaultURL_devEnv() { + String url = Utils.getVaultURL("cluster1", Env.DEV); + Assert.assertEquals("https://cluster1.skyvault.skyflowapis.dev", url); + } + + @Test + public void testGetVaultURL_stageEnv() { + String url = Utils.getVaultURL("cluster1", Env.STAGE); + Assert.assertEquals("https://cluster1.skyvault.skyflowapis.tech", url); + } + + @Test + public void testGetVaultURL_sandboxEnv() { + String url = Utils.getVaultURL("cluster1", Env.SANDBOX); + Assert.assertEquals("https://cluster1.skyvault.skyflowapis-preview.com", url); + } + + // ── getMetrics ──────────────────────────────────────────────────────────── + + @Test + public void testGetMetrics_containsSdkVersion() { + JsonObject metrics = Utils.getMetrics(); + Assert.assertTrue(metrics.has(BaseConstants.SDK_METRIC_NAME_VERSION)); + String sdkVersionMetric = metrics.get(BaseConstants.SDK_METRIC_NAME_VERSION).getAsString(); + Assert.assertTrue(sdkVersionMetric.startsWith(Constants.SDK_METRIC_NAME_VERSION_PREFIX)); + } + + // ── getEnvVaultURL ──────────────────────────────────────────────────────── + + @Test + public void testGetEnvVaultURL_doesNotThrowUnexpectedException() { + try { + Utils.getEnvVaultURL(); + } catch (SkyflowException e) { + // acceptable if this environment happens to have an invalid VAULT_URL set + Assert.assertNotNull(e.getMessage()); + } + } + + // ── isValidURL ──────────────────────────────────────────────────────────── + + @Test + public void testIsValidURL_validHttpsUrl() { + Assert.assertTrue(Utils.isValidURL("https://example.com")); + } + + @Test + public void testIsValidURL_httpUrlIsInvalid() { + Assert.assertFalse(Utils.isValidURL("http://example.com")); + } + + @Test + public void testIsValidURL_malformedUrl() { + Assert.assertFalse(Utils.isValidURL("not a url")); + } + + // ── generateBearerToken ─────────────────────────────────────────────────── + + @Test + public void testGenerateBearerToken_withDirectToken() throws SkyflowException { + Credentials credentials = new Credentials(); + credentials.setToken("direct-token-value"); + + String token = Utils.generateBearerToken(credentials); + + Assert.assertEquals("direct-token-value", token); + } + + @Test + public void testGenerateBearerToken_withInvalidCredentialsStringThrows() { + Credentials credentials = new Credentials(); + // A string that fails JSON syntax parsing (as opposed to e.g. a bare word, + // which Gson's lenient parser accepts as a JSON primitive rather than rejecting outright). + credentials.setCredentialsString("./src/test/credentials.json"); + try { + Utils.generateBearerToken(credentials); + Assert.fail("Should have thrown an exception"); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testGenerateBearerToken_withNonExistentPathThrows() { + Credentials credentials = new Credentials(); + credentials.setPath("/nonexistent/path/credentials.json"); + try { + Utils.generateBearerToken(credentials); + Assert.fail("Should have thrown an exception"); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── getBulkInsertRequestBody ────────────────────────────────────────────── + + @Test + public void testGetBulkInsertRequestBody_buildsCorrectRequest() { + Map data = new HashMap<>(); + data.put("name", "john"); + InsertRecord record = InsertRecord.builder().data(data).build(); + ArrayList records = new ArrayList<>(); + records.add(record); + InsertRequest request = InsertRequest.builder().table("table1").records(records).build(); + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + + V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals("table1", body.getTableName().get()); + Assert.assertEquals(1, body.getRecords().get().size()); + Assert.assertEquals(data, body.getRecords().get().get(0).getData().get()); + } + + @Test + public void testGetBulkInsertRequestBody_withUpsertAtRequestLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + InsertRecord record = InsertRecord.builder().data(data).build(); + ArrayList records = new ArrayList<>(); + records.add(record); + InsertRequest request = InsertRequest.builder() + .table("table1") + .records(records) + .upsert(Collections.singletonList("email")) + .upsertType(UpsertType.UPDATE) + .build(); + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + + V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + + Assert.assertTrue(body.getUpsert().isPresent()); + Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns().get()); + Assert.assertEquals(FlowEnumUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); + } + + @Test + public void testGetBulkInsertRequestBody_withUpsertAtRecordLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + InsertRecord record = InsertRecord.builder() + .table("table1") + .data(data) + .upsert(Collections.singletonList("email")) + .upsertType(UpsertType.REPLACE) + .build(); + ArrayList records = new ArrayList<>(); + records.add(record); + InsertRequest request = InsertRequest.builder().records(records).build(); + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + + V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + + Assert.assertEquals("table1", body.getRecords().get().get(0).getTableName().get()); + Assert.assertTrue(body.getRecords().get().get(0).getUpsert().isPresent()); + Assert.assertEquals(FlowEnumUpdateType.REPLACE, body.getRecords().get().get(0).getUpsert().get().getUpdateType().get()); + } + + // ── buildInsertResponse ─────────────────────────────────────────────────── + + @Test + public void testBuildInsertResponse_success() { + Map tokens = new HashMap<>(); + tokens.put("name", "tok-abc"); + V1RecordResponseObject record = V1RecordResponseObject.builder() + .skyflowId("sky-id-1") + .tokens(tokens) + .build(); + V1InsertResponse res = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + + InsertResponse response = Utils.buildInsertResponse(res); + + Assert.assertEquals(1, response.getInsertedFields().size()); + Assert.assertEquals("sky-id-1", response.getInsertedFields().get(0).get("skyflowId")); + Assert.assertEquals("tok-abc", response.getInsertedFields().get(0).get("name")); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildInsertResponse_error() { + V1RecordResponseObject record = V1RecordResponseObject.builder() + .skyflowId("sky-id-1") + .tableName("table1") + .error("insert failed") + .httpCode(400) + .build(); + V1InsertResponse res = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + + InsertResponse response = Utils.buildInsertResponse(res); + + Assert.assertTrue(response.getInsertedFields().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals("insert failed", response.getErrors().get(0).get("error")); + Assert.assertEquals("table1", response.getErrors().get(0).get("tableName")); + Assert.assertEquals(400, response.getErrors().get(0).get("httpCode")); + } + + @Test + public void testBuildInsertResponse_nullResponse() { + InsertResponse response = Utils.buildInsertResponse(null); + Assert.assertTrue(response.getInsertedFields().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildInsertResponse_emptyResponse() { + V1InsertResponse res = V1InsertResponse.builder().build(); + InsertResponse response = Utils.buildInsertResponse(res); + Assert.assertTrue(response.getInsertedFields().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + // ── getDetokenizeRequestBody ────────────────────────────────────────────── + + @Test + public void testGetDetokenizeRequestBody_buildsCorrectRequest() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + + V1FlowDetokenizeRequest body = Utils.getDetokenizeRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals(Collections.singletonList("token1"), body.getTokens().get()); + Assert.assertFalse(body.getTokenGroupRedactions().isPresent()); + } + + @Test + public void testGetDetokenizeRequestBody_withTokenGroupRedactions() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + List groupRedactions = Collections.singletonList( + TokenGroupRedactions.builder().tokenGroupName("group1").redaction("MASKED").build()); + DetokenizeRequest request = DetokenizeRequest.builder() + .detokenizeData(data) + .tokenGroupRedactions(groupRedactions) + .build(); + + V1FlowDetokenizeRequest body = Utils.getDetokenizeRequestBody(request, "vault123"); + + Assert.assertTrue(body.getTokenGroupRedactions().isPresent()); + Assert.assertEquals("group1", body.getTokenGroupRedactions().get().get(0).getTokenGroupName().get()); + Assert.assertEquals("MASKED", body.getTokenGroupRedactions().get().get(0).getRedaction().get()); + } + + // ── buildDetokenizeResponse ─────────────────────────────────────────────── + + @Test + public void testBuildDetokenizeResponse_success() { + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1") + .value("secret-value") + .tokenGroupName("group1") + .build(); + V1FlowDetokenizeResponse res = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)) + .build(); + + DetokenizeResponse response = Utils.buildDetokenizeResponse(res); + + Assert.assertEquals(1, response.getDetokenizedFields().size()); + DetokenizeRecordResponse detokenizedField = response.getDetokenizedFields().get(0); + Assert.assertEquals("token1", detokenizedField.getToken()); + Assert.assertEquals("secret-value", detokenizedField.getValue()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildDetokenizeResponse_error() { + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1") + .error("detokenize failed") + .build(); + V1FlowDetokenizeResponse res = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)) + .build(); + + DetokenizeResponse response = Utils.buildDetokenizeResponse(res); + + Assert.assertTrue(response.getDetokenizedFields().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals("detokenize failed", response.getErrors().get(0).getError()); + } + + @Test + public void testBuildDetokenizeResponse_nullResponse() { + DetokenizeResponse response = Utils.buildDetokenizeResponse(null); + Assert.assertTrue(response.getDetokenizedFields().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + // ── getTokenizeRequestBody ──────────────────────────────────────────────── + + @Test + public void testGetTokenizeRequestBody_buildsCorrectRequest() { + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder() + .value("value1") + .tokenGroupNames(Collections.singletonList("group1")) + .build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + + V1FlowTokenizeRequest body = Utils.getTokenizeRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertTrue(body.getData().isPresent()); + Assert.assertEquals(1, body.getData().get().size()); + Assert.assertEquals("value1", body.getData().get().get(0).getValue().get()); + Assert.assertEquals(Collections.singletonList("group1"), body.getData().get().get(0).getTokenGroupNames().get()); + } + + // ── buildTokenizeResponse ───────────────────────────────────────────────── + + @Test + public void testBuildTokenizeResponse_success() { + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1") + .token("tok-abc") + .build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1") + .tokens(Collections.singletonList(token)) + .build(); + V1FlowTokenizeResponse res = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)) + .build(); + + TokenizeResponse response = Utils.buildTokenizeResponse(res, new HashMap<>(), 1); + + Assert.assertEquals(1, response.getTokenizedData().size()); + TokenizeData data = response.getTokenizedData().get(0); + Assert.assertEquals("value1", data.getValue()); + Assert.assertEquals("tok-abc", data.getTokens().get("group1")); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildTokenizeResponse_error() { + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1") + .error("tokenization failed") + .httpCode(400) + .build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1") + .tokens(Collections.singletonList(token)) + .build(); + V1FlowTokenizeResponse res = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)) + .build(); + + TokenizeResponse response = Utils.buildTokenizeResponse(res, new HashMap<>(), 1); + + Assert.assertTrue(response.getTokenizedData().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Map errorRecord = response.getErrors().get(0); + Assert.assertEquals("tokenization failed", errorRecord.get("error")); + Assert.assertEquals(400, errorRecord.get("httpCode")); + Assert.assertEquals("group1", errorRecord.get("tokenGroupName")); + Assert.assertEquals(0, errorRecord.get("index")); + } + + @Test + public void testBuildTokenizeResponse_mixedSuccessAndError() { + FlowTokenizeResponseObjectToken successToken = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1") + .token("tok-abc") + .build(); + FlowTokenizeResponseObjectToken errorToken = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group2") + .error("group2 failed") + .httpCode(400) + .build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1") + .tokens(java.util.Arrays.asList(successToken, errorToken)) + .build(); + V1FlowTokenizeResponse res = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)) + .build(); + + TokenizeResponse response = Utils.buildTokenizeResponse(res, new HashMap<>(), 1); + + Assert.assertEquals(1, response.getTokenizedData().size()); + Assert.assertEquals("tok-abc", response.getTokenizedData().get(0).getTokens().get("group1")); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals("group2 failed", response.getErrors().get(0).get("error")); + } + + @Test + public void testBuildTokenizeResponse_emptyResponse() { + V1FlowTokenizeResponse res = V1FlowTokenizeResponse.builder().build(); + + TokenizeResponse response = Utils.buildTokenizeResponse(res, new HashMap<>(), 1); + + Assert.assertTrue(response.getTokenizedData().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildTokenizeResponse_nullResponse() { + TokenizeResponse response = Utils.buildTokenizeResponse(null, new HashMap<>(), 1); + + Assert.assertTrue(response.getTokenizedData().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildTokenizeResponse_incompleteResponseDoesNotThrow() { + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1") + .token("tok-abc") + .build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1") + .tokens(Collections.singletonList(token)) + .build(); + V1FlowTokenizeResponse res = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)) + .build(); + + // requestedRecordCount=2 but only 1 record came back — should just warn, not throw + TokenizeResponse response = Utils.buildTokenizeResponse(res, new HashMap<>(), 2); + + Assert.assertEquals(1, response.getTokenizedData().size()); + } + + // ── getDeleteTokensRequestBody ──────────────────────────────────────────── + + @Test + public void testGetDeleteTokensRequestBody_buildsCorrectRequest() { + DeleteTokensRequest request = DeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + V1FlowDeleteTokenRequest body = Utils.getDeleteTokensRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals(Collections.singletonList("token1"), body.getTokens().get()); + } + + // ── buildDeleteTokensResponse ───────────────────────────────────────────── + + @Test + public void testBuildDeleteTokensResponse_success() { + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + .value("token1") + .build(); + V1FlowDeleteTokenResponse res = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)) + .build(); + + DeleteTokensResponse response = Utils.buildDeleteTokensResponse(res, new HashMap<>(), 1); + + Assert.assertEquals(Collections.singletonList("token1"), response.getTokens()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildDeleteTokensResponse_error() { + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + .error("token not found") + .httpCode(404) + .build(); + V1FlowDeleteTokenResponse res = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)) + .build(); + + DeleteTokensResponse response = Utils.buildDeleteTokensResponse(res, new HashMap<>(), 1); + + Assert.assertTrue(response.getTokens().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals("token not found", response.getErrors().get(0).get("error")); + Assert.assertEquals(404, response.getErrors().get(0).get("httpCode")); + } + + @Test + public void testBuildDeleteTokensResponse_emptyResponse() { + V1FlowDeleteTokenResponse res = V1FlowDeleteTokenResponse.builder().build(); + + DeleteTokensResponse response = Utils.buildDeleteTokensResponse(res, new HashMap<>(), 1); + + Assert.assertTrue(response.getTokens().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildDeleteTokensResponse_nullResponse() { + DeleteTokensResponse response = Utils.buildDeleteTokensResponse(null, new HashMap<>(), 1); + + Assert.assertTrue(response.getTokens().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBuildDeleteTokensResponse_incompleteResponseDoesNotThrow() { + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + .value("token1") + .build(); + V1FlowDeleteTokenResponse res = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)) + .build(); + + // requestedTokenCount=2 but only 1 record came back — should just warn, not throw + DeleteTokensResponse response = Utils.buildDeleteTokensResponse(res, new HashMap<>(), 2); + + Assert.assertEquals(1, response.getTokens().size()); + } +} diff --git a/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java new file mode 100644 index 00000000..2167fd30 --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java @@ -0,0 +1,732 @@ +package com.skyflow.utils.validations; + +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.Env; +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.data.DeleteTokensRequest; +import com.skyflow.vault.data.DetokenizeData; +import com.skyflow.vault.data.DetokenizeRequest; +import com.skyflow.vault.data.InsertRecord; +import com.skyflow.vault.data.InsertRequest; +import com.skyflow.vault.data.TokenGroupRedactions; +import com.skyflow.vault.data.TokenizeRecord; +import com.skyflow.vault.data.TokenizeRequest; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ValidationsTests { + private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; + + // ── validateTokenizeRequest ────────────────────────────────────────────── + + @Test + public void testValidateTokenizeRequest_nullRequest() { + try { + Validations.validateTokenizeRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_nullData() { + TokenizeRequest request = TokenizeRequest.builder().data(null).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_emptyData() { + TokenizeRequest request = TokenizeRequest.builder().data(new ArrayList<>()).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_largeValidListDoesNotThrow() { + ArrayList records = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + records.add(TokenizeRecord.builder() + .value("value" + i) + .tokenGroupNames(Collections.singletonList("group1")) + .build()); + } + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateTokenizeRequest_nullRecordInList() { + ArrayList records = new ArrayList<>(); + records.add(null); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_nullValue() { + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder().value(null).tokenGroupNames(Collections.singletonList("group1")).build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_blankStringValue() { + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder().value(" ").tokenGroupNames(Collections.singletonList("group1")).build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_nullTokenGroupNames() { + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder().value("value1").tokenGroupNames(null).build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_emptyTokenGroupNames() { + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder().value("value1").tokenGroupNames(new ArrayList<>()).build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_blankTokenGroupNameAtIndex() { + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder() + .value("value1") + .tokenGroupNames(Arrays.asList("group1", " ")) + .build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateTokenizeRequest_validRequest() { + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder() + .value("value1") + .tokenGroupNames(Collections.singletonList("group1")) + .build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + try { + Validations.validateTokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateDeleteTokensRequest ────────────────────────────────────────── + + @Test + public void testValidateDeleteTokensRequest_nullRequest() { + try { + Validations.validateDeleteTokensRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDeleteTokensRequest_nullTokens() { + DeleteTokensRequest request = DeleteTokensRequest.builder().tokens(null).build(); + try { + Validations.validateDeleteTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDeleteTokensRequest_emptyTokens() { + DeleteTokensRequest request = DeleteTokensRequest.builder().tokens(new ArrayList<>()).build(); + try { + Validations.validateDeleteTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDeleteTokensRequest_largeValidListDoesNotThrow() { + List tokens = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + tokens.add("token" + i); + } + DeleteTokensRequest request = DeleteTokensRequest.builder().tokens(tokens).build(); + try { + Validations.validateDeleteTokensRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateDeleteTokensRequest_blankTokenAtIndex() { + DeleteTokensRequest request = DeleteTokensRequest.builder() + .tokens(Arrays.asList("token1", " ")) + .build(); + try { + Validations.validateDeleteTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDeleteTokensRequest_validRequest() { + DeleteTokensRequest request = DeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + try { + Validations.validateDeleteTokensRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateCredentials ─────────────────────────────────────────────────── + + @Test + public void testValidateCredentials_validToken() { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + try { + Validations.validateCredentials(credentials); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateCredentials_validApiKey() { + Credentials credentials = new Credentials(); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + try { + Validations.validateCredentials(credentials); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateCredentials_invalidApiKeyFormat() { + Credentials credentials = new Credentials(); + credentials.setApiKey("not-a-valid-api-key"); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_noAuthMeansPassed() { + Credentials credentials = new Credentials(); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_multipleAuthMeansPassed() { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_emptyRoles() { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + credentials.setRoles(new ArrayList<>()); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── validateVaultConfiguration ──────────────────────────────────────────── + + @Test + public void testValidateVaultConfiguration_nullVaultId() { + VaultConfig config = new VaultConfig(); + config.setClusterId("cluster1"); + try { + Validations.validateVaultConfiguration(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateVaultConfiguration_emptyVaultId() { + VaultConfig config = new VaultConfig(); + config.setVaultId(" "); + config.setClusterId("cluster1"); + try { + Validations.validateVaultConfiguration(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateVaultConfiguration_neitherVaultUrlNorClusterId() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + try { + Validations.validateVaultConfiguration(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateVaultConfiguration_emptyClusterId() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId(" "); + try { + Validations.validateVaultConfiguration(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateVaultConfiguration_emptyVaultUrl() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId("cluster1"); + config.setVaultURL(" "); + try { + Validations.validateVaultConfiguration(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateVaultConfiguration_invalidVaultUrlFormat() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setVaultURL("http://not-https.example.com"); + try { + Validations.validateVaultConfiguration(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateVaultConfiguration_validWithClusterId() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId("cluster1"); + config.setEnv(Env.DEV); + try { + Validations.validateVaultConfiguration(config); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateVaultConfiguration_validWithVaultUrl() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setVaultURL("https://myvault.example.com"); + try { + Validations.validateVaultConfiguration(config); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateVaultConfiguration_delegatesToCredentialValidation() { + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId("cluster1"); + Credentials credentials = new Credentials(); + credentials.setApiKey("not-a-valid-api-key"); + config.setCredentials(credentials); + try { + Validations.validateVaultConfiguration(config); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── validateInsertRequest ───────────────────────────────────────────────── + + @Test + public void testValidateInsertRequest_nullRecords() { + InsertRequest request = InsertRequest.builder().table("table1").records(null).build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_emptyRecords() { + InsertRequest request = InsertRequest.builder().table("table1").records(new ArrayList<>()).build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_nullRecordInList() { + ArrayList records = new ArrayList<>(); + records.add(null); + InsertRequest request = InsertRequest.builder().table("table1").records(records).build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_tableSpecifiedAtBothPlaces() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("recordTable").data(data).build()); + InsertRequest request = InsertRequest.builder().table("requestTable").records(records).build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_tableMissingAtBothPlaces() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_upsertAtRecordLevelWhenTableAtRequestLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().data(data).upsert(Collections.singletonList("email")).build()); + InsertRequest request = InsertRequest.builder() + .table("table1") + .records(records) + .build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_emptyUpsertAtRequestLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().data(data).build()); + InsertRequest request = InsertRequest.builder() + .table("table1") + .records(records) + .upsert(new ArrayList<>()) + .build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_emptyOrNullKeyInData() { + Map data = new HashMap<>(); + data.put("", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_emptyOrNullValueInData() { + Map data = new HashMap<>(); + data.put("name", ""); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateInsertRequest_validRequest() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + try { + Validations.validateInsertRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateDetokenizeRequest ───────────────────────────────────────────── + + @Test + public void testValidateDetokenizeRequest_nullRequest() { + try { + Validations.validateDetokenizeRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_nullDetokenizeData() { + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(null).build(); + try { + Validations.validateDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_emptyDetokenizeData() { + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(new ArrayList<>()).build(); + try { + Validations.validateDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_nullEntryInDetokenizeData() { + ArrayList data = new ArrayList<>(); + data.add(null); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + try { + Validations.validateDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_blankTokenInDetokenizeData() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData(" ")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + try { + Validations.validateDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_nullTokenGroupRedactionInList() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + List groupRedactions = new ArrayList<>(); + groupRedactions.add(null); + DetokenizeRequest request = DetokenizeRequest.builder() + .detokenizeData(data) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_blankTokenGroupNameInRedaction() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + List groupRedactions = Collections.singletonList( + TokenGroupRedactions.builder().tokenGroupName(" ").redaction("MASKED").build()); + DetokenizeRequest request = DetokenizeRequest.builder() + .detokenizeData(data) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_blankRedactionInGroup() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + List groupRedactions = Collections.singletonList( + TokenGroupRedactions.builder().tokenGroupName("group1").redaction(" ").build()); + DetokenizeRequest request = DetokenizeRequest.builder() + .detokenizeData(data) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateDetokenizeRequest_validRequest() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + try { + Validations.validateDetokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateDetokenizeRequest_validRequestWithTokenGroupRedactions() { + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + List groupRedactions = Collections.singletonList( + TokenGroupRedactions.builder().tokenGroupName("group1").redaction("MASKED").build()); + DetokenizeRequest request = DetokenizeRequest.builder() + .detokenizeData(data) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateDetokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } +} diff --git a/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java new file mode 100644 index 00000000..78d6aadd --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java @@ -0,0 +1,445 @@ +package com.skyflow.vault.controller; + +import com.skyflow.VaultClient; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.Env; +import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.ApiClient; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; +import com.skyflow.generated.rest.resources.flowservice.RawFlowserviceClient; +import com.skyflow.generated.rest.types.FlowTokenizeResponseObjectToken; +import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; +import com.skyflow.generated.rest.types.V1FlowDetokenizeResponse; +import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; +import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; +import com.skyflow.generated.rest.types.V1FlowTokenizeResponseObject; +import com.skyflow.generated.rest.types.V1InsertResponse; +import com.skyflow.generated.rest.types.V1RecordResponseObject; +import com.skyflow.utils.Constants; +import com.skyflow.vault.data.DeleteTokensRequest; +import com.skyflow.vault.data.DeleteTokensResponse; +import com.skyflow.vault.data.DetokenizeData; +import com.skyflow.vault.data.DetokenizeRequest; +import com.skyflow.vault.data.DetokenizeResponse; +import com.skyflow.vault.data.InsertRecord; +import com.skyflow.vault.data.InsertRequest; +import com.skyflow.vault.data.InsertResponse; +import com.skyflow.vault.data.TokenizeRecord; +import com.skyflow.vault.data.TokenizeRequest; +import com.skyflow.vault.data.TokenizeResponse; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +public class VaultControllerTests { + private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; + + private static VaultController createControllerWithMock(ApiClient mockApiClient) throws Exception { + Credentials creds = new Credentials(); + creds.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId("cluster123"); + config.setEnv(Env.DEV); + + VaultController controller = new VaultController(config, creds); + Field field = VaultClient.class.getDeclaredField("apiClient"); + field.setAccessible(true); + field.set(controller, mockApiClient); + return controller; + } + + private static Response buildOkHttpResponse() { + return new Response.Builder() + .request(new Request.Builder().url("https://dummy.example.com").build()) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("OK") + .header(Constants.REQUEST_ID_HEADER_KEY, "req-test-123") + .build(); + } + + private static RawFlowserviceClient mockRawFlowservice(ApiClient mockApi) { + FlowserviceClient mockFlowservice = Mockito.mock(FlowserviceClient.class); + RawFlowserviceClient mockRaw = Mockito.mock(RawFlowserviceClient.class); + when(mockApi.flowservice()).thenReturn(mockFlowservice); + when(mockFlowservice.withRawResponse()).thenReturn(mockRaw); + return mockRaw; + } + + // ── insert ──────────────────────────────────────────────────────────────── + + @Test + public void testInsert_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokens = new HashMap<>(); + tokens.put("name", "tok-abc"); + V1RecordResponseObject record = V1RecordResponseObject.builder() + .skyflowId("sky-id-1") + .tokens(tokens) + .build(); + V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.insert(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + + InsertResponse response = controller.insert(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getInsertedFields().size()); + Assert.assertEquals("sky-id-1", response.getInsertedFields().get(0).get("skyflowId")); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testInsert_apiErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.insert(any(), any())) + .thenThrow(new ApiClientApiException("insert failed", 401, "unauthorized")); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + + try { + controller.insert(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(401, e.getHttpCode()); + } + } + + @Test + public void testInsert_networkErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.insert(any(), any())) + .thenThrow(new ApiClientException("Network error executing HTTP request")); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + + try { + controller.insert(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testInsert_invalidRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + InsertRequest request = InsertRequest.builder().records(new ArrayList<>()).build(); + try { + controller.insert(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── detokenize ──────────────────────────────────────────────────────────── + + @Test + public void testDetokenize_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1") + .value("secret-value") + .build(); + V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)) + .build(); + ApiClientHttpResponse httpResp = + new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + + DetokenizeResponse response = controller.detokenize(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getDetokenizedFields().size()); + Assert.assertEquals("secret-value", response.getDetokenizedFields().get(0).getValue()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testDetokenize_apiErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.detokenize(any(), any())) + .thenThrow(new ApiClientApiException("detokenize failed", 401, "unauthorized")); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + + try { + controller.detokenize(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(401, e.getHttpCode()); + } + } + + @Test + public void testDetokenize_networkErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.detokenize(any(), any())) + .thenThrow(new ApiClientException("Network error executing HTTP request")); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + + try { + controller.detokenize(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testDetokenize_nullRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.detokenize(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── tokenize ────────────────────────────────────────────────────────────── + + @Test + public void testTokenize_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1") + .token("tok-abc") + .build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1") + .tokens(Collections.singletonList(token)) + .build(); + V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)) + .build(); + ApiClientHttpResponse httpResp = + new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder() + .value("value1") + .tokenGroupNames(Collections.singletonList("group1")) + .build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + + TokenizeResponse response = controller.tokenize(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getTokenizedData().size()); + Assert.assertEquals("tok-abc", response.getTokenizedData().get(0).getTokens().get("group1")); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testTokenize_apiErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokenize(any(), any())) + .thenThrow(new ApiClientApiException("tokenize failed", 401, "unauthorized")); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder() + .value("value1") + .tokenGroupNames(Collections.singletonList("group1")) + .build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + + try { + controller.tokenize(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(401, e.getHttpCode()); + } + } + + @Test + public void testTokenize_networkErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokenize(any(), any())) + .thenThrow(new ApiClientException("Network error executing HTTP request")); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder() + .value("value1") + .tokenGroupNames(Collections.singletonList("group1")) + .build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + + try { + controller.tokenize(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testTokenize_nullRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.tokenize(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + // ── deleteTokens ────────────────────────────────────────────────────────── + + @Test + public void testDeleteTokens_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + .value("token1") + .build(); + V1FlowDeleteTokenResponse body = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)) + .build(); + ApiClientHttpResponse httpResp = + new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.deletetoken(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + DeleteTokensRequest request = DeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + DeleteTokensResponse response = controller.deleteTokens(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(Collections.singletonList("token1"), response.getTokens()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testDeleteTokens_apiErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.deletetoken(any(), any())) + .thenThrow(new ApiClientApiException("delete failed", 404, "not found")); + + VaultController controller = createControllerWithMock(mockApi); + + DeleteTokensRequest request = DeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + try { + controller.deleteTokens(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(404, e.getHttpCode()); + } + } + + @Test + public void testDeleteTokens_networkErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.deletetoken(any(), any())) + .thenThrow(new ApiClientException("Network error executing HTTP request")); + + VaultController controller = createControllerWithMock(mockApi); + + DeleteTokensRequest request = DeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + try { + controller.deleteTokens(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testDeleteTokens_nullRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.deleteTokens(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } +} diff --git a/v2/src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java b/v2/src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java index d8d8072b..c77787cf 100644 --- a/v2/src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java +++ b/v2/src/main/java/com/skyflow/vault/tokens/TokenizeResponse.java @@ -1,9 +1,13 @@ package com.skyflow.vault.tokens; -import com.google.gson.*; - import java.util.List; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + public class TokenizeResponse { private final List tokens; From 556e552ef74316ff67b7ec86caa6b2200e40ec75 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 18:13:56 +0530 Subject: [PATCH 14/28] SK-2967 fix internal release workflows --- .../workflows/flowvault-internal-release.yml | 27 ------------------ .github/workflows/internal-release.yml | 28 +++++++++++++++---- 2 files changed, 22 insertions(+), 33 deletions(-) delete mode 100644 .github/workflows/flowvault-internal-release.yml diff --git a/.github/workflows/flowvault-internal-release.yml b/.github/workflows/flowvault-internal-release.yml deleted file mode 100644 index b1e65c12..00000000 --- a/.github/workflows/flowvault-internal-release.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Publish v3 module to the JFROG Artifactory -on: - push: - tags-ignore: - - '*.*' - paths-ignore: - - "*.md" - branches: - - v3-release/* - -jobs: - build-and-deploy-v3: - uses: ./.github/workflows/shared-build-and-deploy.yml - with: - ref: ${{ github.ref_name }} - server-id: central - profile: jfrog - tag: 'internal' - module: 'flowvault' - secrets: - server-username: ${{ secrets.ARTIFACTORY_USERNAME }} - server-password: ${{ secrets.ARTIFACTORY_PASSWORD }} - gpg-key: ${{ secrets.JFROG_GPG_KEY }} - gpg-passphrase: ${{ secrets.JFROG_GPG_PASSPHRASE }} - skyflow-credentials: ${{ secrets.SKYFLOW_CREDENTIALS }} - test-expired-token: ${{ secrets.TEST_EXPIRED_TOKEN }} - test-reusable-token: ${{ secrets.TEST_REUSABLE_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/internal-release.yml b/.github/workflows/internal-release.yml index 70a33281..a246a6e3 100644 --- a/.github/workflows/internal-release.yml +++ b/.github/workflows/internal-release.yml @@ -1,4 +1,4 @@ -name: Publish v2 module to the JFROG Artifactory +name: Publish module to the JFROG Artifactory on: push: tags-ignore: @@ -7,21 +7,37 @@ on: - "*.md" branches: - release/* + - flowvault-release/* jobs: - build-and-deploy-v2: + resolve-module: + runs-on: ubuntu-latest + outputs: + module: ${{ steps.set-module.outputs.module }} + steps: + - name: Resolve module from branch name + id: set-module + run: | + if [[ "${{ github.ref_name }}" == flowvault-release/* ]]; then + echo "module=flowvault" >> "$GITHUB_OUTPUT" + else + echo "module=v2" >> "$GITHUB_OUTPUT" + fi + + build-and-deploy: + needs: resolve-module uses: ./.github/workflows/shared-build-and-deploy.yml with: ref: ${{ github.ref_name }} server-id: central profile: jfrog tag: 'internal' - module: 'v2' + module: ${{ needs.resolve-module.outputs.module }} secrets: server-username: ${{ secrets.ARTIFACTORY_USERNAME }} server-password: ${{ secrets.ARTIFACTORY_PASSWORD }} gpg-key: ${{ secrets.JFROG_GPG_KEY }} gpg-passphrase: ${{ secrets.JFROG_GPG_PASSPHRASE }} - skyflow-credentials: ${{ secrets.SKYFLOW_CREDENTIALS }} >> .env - test-expired-token: ${{ secrets.TEST_EXPIRED_TOKEN }} >> .env - test-reusable-token: ${{ secrets.TEST_REUSABLE_TOKEN }} >> .env + skyflow-credentials: ${{ secrets.SKYFLOW_CREDENTIALS }} + test-expired-token: ${{ secrets.TEST_EXPIRED_TOKEN }} + test-reusable-token: ${{ secrets.TEST_REUSABLE_TOKEN }} From 7cea4eb8bb1384a7c1394563ffdb97a01dfa07c5 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 12:45:52 +0000 Subject: [PATCH 15/28] [AUTOMATED] Private Release 1.15.1-dev-cd30d53 --- v2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/pom.xml b/v2/pom.xml index 01370ded..581c615a 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -11,7 +11,7 @@ skyflow-java - 1.15.1-dev.807824c + 1.15.1-dev.cd30d53 com.skyflow From eacdd60983997bfa2d3eb892c14c7bdaa5a8b0da Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 18:21:06 +0530 Subject: [PATCH 16/28] SK-2967 fix internal release workflows --- v2/pom.xml | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/v2/pom.xml b/v2/pom.xml index b35a9552..088affcd 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -48,4 +48,49 @@ + + + jfrog + + + central + prekarilabs.jfrog.io-releases + https://prekarilabs.jfrog.io/artifactory/skyflow-java + + + snapshots + prekarilabs.jfrog.io-snapshots + https://prekarilabs.jfrog.io/artifactory/skyflow-java + + + + + maven-central + + + central + https://central.sonatype.com/api/v1/publisher/upload + + + central-snapshots + https://central.sonatype.com/api/v1/publisher/upload + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.4.0 + true + + central + true + true + + + + + + \ No newline at end of file From f1763a52e8212137716e0a04d8d5f09377347f16 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 13:19:43 +0000 Subject: [PATCH 17/28] [AUTOMATED] Private Release 1.15.1-dev-139086e --- v2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/pom.xml b/v2/pom.xml index a25cc846..8d634de3 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -11,7 +11,7 @@ skyflow-java - 1.15.1-dev.cd30d53 + 1.15.1-dev.139086e com.skyflow From d161a4224a9ed499bbbfa54f1724d173dd606266 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 19:09:03 +0530 Subject: [PATCH 18/28] SK-2967 fix internal release workflows --- .github/workflows/shared-build-and-deploy.yml | 2 +- v2/pom.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shared-build-and-deploy.yml b/.github/workflows/shared-build-and-deploy.yml index 77615306..174504cd 100644 --- a/.github/workflows/shared-build-and-deploy.yml +++ b/.github/workflows/shared-build-and-deploy.yml @@ -59,7 +59,7 @@ jobs: fetch-depth: 0 - name: Set up maven or jfrog repository - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: java-version: "11" distribution: "adopt" diff --git a/v2/pom.xml b/v2/pom.xml index a25cc846..f143b99a 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -11,10 +11,11 @@ skyflow-java - 1.15.1-dev.cd30d53 + 2.1.1 com.skyflow + false 8 8 UTF-8 From 08e1761c708129a50b13c18041b120e627768af0 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 19:30:26 +0530 Subject: [PATCH 19/28] SK-2967 fix internal release workflows --- v2/pom.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/v2/pom.xml b/v2/pom.xml index f143b99a..bd4f72e8 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -47,6 +47,26 @@ 9 + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + com.skyflow:common + + + + + + From 7dd73d502a282819aec87c88f720e95f93a5801d Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Fri, 17 Jul 2026 23:02:14 +0530 Subject: [PATCH 20/28] SK-2967 fix internal release workflows --- pom.xml | 2 +- v2/pom.xml | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index ec74443b..9dc3d230 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ io.github.cdimascio dotenv-java - 3.2.0 + 2.2.0 com.google.code.gson diff --git a/v2/pom.xml b/v2/pom.xml index bd4f72e8..9207abe0 100644 --- a/v2/pom.xml +++ b/v2/pom.xml @@ -39,14 +39,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - 9 - 9 - - org.apache.maven.plugins maven-shade-plugin From 5ee3646f869ff35a45acdb71b7fd0e9f136c1373 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Sat, 18 Jul 2026 01:11:41 +0530 Subject: [PATCH 21/28] SK-2967 add back the bulk interfaces --- .../com/skyflow/enums/CustomHeaderKey.java | 2 +- .../skyflow/vault/data/RequestContext.java | 2 +- .../vault/data/RequestInterceptor.java | 0 .../main/java/com/skyflow/utils/Utils.java | 538 ++++++++++ .../utils/validations/Validations.java | 227 ++++ .../vault/controller/VaultController.java | 984 +++++++++++++++++- .../vault/data/BulkDeleteTokensRequest.java | 34 + .../vault/data/BulkDeleteTokensResponse.java | 50 + .../vault/data/BulkDetokenizeRequest.java | 41 + .../vault/data/BulkDetokenizeResponse.java | 63 ++ .../skyflow/vault/data/BulkInsertRecord.java | 68 ++ .../skyflow/vault/data/BulkInsertRequest.java | 69 ++ .../vault/data/BulkInsertResponse.java | 68 ++ .../vault/data/BulkTokenGroupRedactions.java | 39 + .../vault/data/BulkTokenizeRecord.java | 44 + .../vault/data/BulkTokenizeRequest.java | 34 + .../vault/data/BulkTokenizeResponse.java | 80 ++ .../vault/data/DeleteTokensOptions.java | 30 + .../vault/data/DeleteTokensSuccess.java | 31 + .../vault/data/DeleteTokensSummary.java | 41 + .../skyflow/vault/data/DetokenizeOptions.java | 30 + .../vault/data/DetokenizeResponseObject.java | 63 ++ .../skyflow/vault/data/DetokenizeSummary.java | 40 + .../com/skyflow/vault/data/ErrorRecord.java | 51 + .../java/com/skyflow/vault/data/Success.java | 53 + .../java/com/skyflow/vault/data/Summary.java | 42 + .../java/com/skyflow/vault/data/Token.java | 23 + .../skyflow/vault/data/TokenizeOptions.java | 30 + .../skyflow/vault/data/TokenizeSuccess.java | 53 + .../skyflow/vault/data/TokenizeSummary.java | 39 + .../java/com/skyflow/utils/UtilsTests.java | 582 +++++++++++ .../utils/validations/ValidationsTests.java | 392 +++++++ .../controller/VaultControllerTests.java | 380 +++++++ 33 files changed, 4215 insertions(+), 8 deletions(-) rename {flowvault => common}/src/main/java/com/skyflow/enums/CustomHeaderKey.java (99%) rename {flowvault => common}/src/main/java/com/skyflow/vault/data/RequestContext.java (88%) rename {flowvault => common}/src/main/java/com/skyflow/vault/data/RequestInterceptor.java (100%) create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRecord.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkInsertResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkTokenGroupRedactions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRecord.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensOptions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSuccess.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSummary.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DetokenizeOptions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponseObject.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/DetokenizeSummary.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/ErrorRecord.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/Success.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/Summary.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/Token.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenizeOptions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenizeSuccess.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/TokenizeSummary.java diff --git a/flowvault/src/main/java/com/skyflow/enums/CustomHeaderKey.java b/common/src/main/java/com/skyflow/enums/CustomHeaderKey.java similarity index 99% rename from flowvault/src/main/java/com/skyflow/enums/CustomHeaderKey.java rename to common/src/main/java/com/skyflow/enums/CustomHeaderKey.java index 8e6190c6..03649eee 100644 --- a/flowvault/src/main/java/com/skyflow/enums/CustomHeaderKey.java +++ b/common/src/main/java/com/skyflow/enums/CustomHeaderKey.java @@ -15,4 +15,4 @@ public enum CustomHeaderKey { public String toString() { return this.value; } -} \ No newline at end of file +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/RequestContext.java b/common/src/main/java/com/skyflow/vault/data/RequestContext.java similarity index 88% rename from flowvault/src/main/java/com/skyflow/vault/data/RequestContext.java rename to common/src/main/java/com/skyflow/vault/data/RequestContext.java index 1473df50..0cf6055b 100644 --- a/flowvault/src/main/java/com/skyflow/vault/data/RequestContext.java +++ b/common/src/main/java/com/skyflow/vault/data/RequestContext.java @@ -10,7 +10,7 @@ public final class RequestContext { private final String operation; private final Map headers = new HashMap<>(); - public RequestContext(String operation, int batchIndex, int totalBatches) { + public RequestContext(String operation) { this.operation = operation; } diff --git a/flowvault/src/main/java/com/skyflow/vault/data/RequestInterceptor.java b/common/src/main/java/com/skyflow/vault/data/RequestInterceptor.java similarity index 100% rename from flowvault/src/main/java/com/skyflow/vault/data/RequestInterceptor.java rename to common/src/main/java/com/skyflow/vault/data/RequestInterceptor.java diff --git a/flowvault/src/main/java/com/skyflow/utils/Utils.java b/flowvault/src/main/java/com/skyflow/utils/Utils.java index cb69453f..db2d00bd 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Utils.java +++ b/flowvault/src/main/java/com/skyflow/utils/Utils.java @@ -326,4 +326,542 @@ public static TokenizeResponse buildTokenizeResponse(V1FlowTokenizeResponse res, tokenizeResponse.setTokenizedData(tokenizedData); return tokenizeResponse; } + + // ── Bulk (batched/concurrent) request-body builders ────────────────────── + + public static com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest getBulkInsertRequestBody(BulkInsertRequest request, VaultConfig config) { + ArrayList records = request.getRecords(); + List insertRecordDataList = new ArrayList<>(); + for (BulkInsertRecord record : records) { + V1InsertRecordData.Builder data = V1InsertRecordData.builder(); + data.data(record.getData()); + if (record.getTable() != null && !record.getTable().isEmpty()) { + data.tableName(record.getTable()); + } + if (record.getUpsert() != null && !record.getUpsert().isEmpty()) { + if (record.getUpsertType() != null) { + FlowEnumUpdateType updateType = null; + if (record.getUpsertType() == UpsertType.REPLACE) { + updateType = FlowEnumUpdateType.REPLACE; + } else if (record.getUpsertType() == UpsertType.UPDATE) { + updateType = FlowEnumUpdateType.UPDATE; + } + V1Upsert upsert = V1Upsert.builder().uniqueColumns(record.getUpsert()).updateType(updateType).build(); + data.upsert(upsert); + } else { + V1Upsert upsert = V1Upsert.builder().uniqueColumns(record.getUpsert()).build(); + data.upsert(upsert); + } + } + insertRecordDataList.add(data.build()); + } + + com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest.Builder builder = + com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest.builder() + .vaultId(config.getVaultId()) + .records(insertRecordDataList); + + if (request.getTable() != null && !request.getTable().isEmpty()) { + builder.tableName(request.getTable()); + } + + if (request.getUpsert() != null && !request.getUpsert().isEmpty()) { + if (request.getUpsertType() != null) { + FlowEnumUpdateType updateType = null; + if (request.getUpsertType() == UpsertType.REPLACE) { + updateType = FlowEnumUpdateType.REPLACE; + } else if (request.getUpsertType() == UpsertType.UPDATE) { + updateType = FlowEnumUpdateType.UPDATE; + } + V1Upsert upsert = V1Upsert.builder().uniqueColumns(request.getUpsert()).updateType(updateType).build(); + builder.upsert(upsert); + } else { + V1Upsert upsert = V1Upsert.builder().uniqueColumns(request.getUpsert()).build(); + builder.upsert(upsert); + } + } + return builder.build(); + } + + public static V1FlowDetokenizeRequest getBulkDetokenizeRequestBody(BulkDetokenizeRequest request, String vaultId) { + V1FlowDetokenizeRequest.Builder builder = V1FlowDetokenizeRequest.builder() + .vaultId(vaultId) + .tokens(request.getTokens()); + if (request.getTokenGroupRedactions() != null && !request.getTokenGroupRedactions().isEmpty()) { + List tokenGroupRedactionsList = new ArrayList<>(); + for (BulkTokenGroupRedactions tokenGroupRedactions : request.getTokenGroupRedactions()) { + tokenGroupRedactionsList.add(V1TokenGroupRedactions.builder() + .tokenGroupName(tokenGroupRedactions.getTokenGroupName()) + .redaction(tokenGroupRedactions.getRedaction()) + .build()); + } + builder.tokenGroupRedactions(tokenGroupRedactionsList); + } + return builder.build(); + } + + public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest getBulkDeleteTokensRequestBody(BulkDeleteTokensRequest request, String vaultId) { + return com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest.builder() + .vaultId(vaultId) + .tokens(request.getTokens()) + .build(); + } + + public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest getBulkTokenizeRequestBody(BulkTokenizeRequest request, String vaultId) { + List dataList = new ArrayList<>(); + for (BulkTokenizeRecord record : request.getData()) { + dataList.add(V1FlowTokenizeRequestObject.builder() + .value(record.getValue()) + .tokenGroupNames(record.getTokenGroupNames()) + .build()); + } + return com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest.builder() + .vaultId(vaultId) + .data(dataList) + .build(); + } + + // ── Bulk batching, exception-handling and response-formatting helpers ──── + + public static List> createBulkInsertBatches(List records, int batchSize) { + List> batches = new ArrayList<>(); + for (int i = 0; i < records.size(); i += batchSize) { + batches.add(records.subList(i, Math.min(i + batchSize, records.size()))); + } + return batches; + } + + public static List createBulkDetokenizeBatches(V1FlowDetokenizeRequest request, int batchSize) { + List detokenizeRequests = new ArrayList<>(); + List tokens = request.getTokens().get(); + + for (int i = 0; i < tokens.size(); i += batchSize) { + List batchTokens = tokens.subList(i, Math.min(i + batchSize, tokens.size())); + List tokenGroupRedactions = null; + if (request.getTokenGroupRedactions().isPresent() && !request.getTokenGroupRedactions().get().isEmpty()) { + tokenGroupRedactions = request.getTokenGroupRedactions().get(); + } + V1FlowDetokenizeRequest batchRequest = V1FlowDetokenizeRequest.builder() + .vaultId(request.getVaultId()) + .tokens(new ArrayList<>(batchTokens)) + .tokenGroupRedactions(tokenGroupRedactions) + .build(); + + detokenizeRequests.add(batchRequest); + } + + return detokenizeRequests; + } + + public static List createBulkDeleteTokensBatches( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest request, int batchSize) { + List batches = new ArrayList<>(); + List tokens = request.getTokens().get(); + for (int i = 0; i < tokens.size(); i += batchSize) { + List batchTokens = tokens.subList(i, Math.min(i + batchSize, tokens.size())); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batchRequest = + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest.builder() + .vaultId(request.getVaultId()) + .tokens(new ArrayList<>(batchTokens)) + .build(); + batches.add(batchRequest); + } + return batches; + } + + public static List createBulkTokenizeBatches( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest request, int batchSize) { + List batches = new ArrayList<>(); + List data = request.getData().get(); + for (int i = 0; i < data.size(); i += batchSize) { + List batchData = data.subList(i, Math.min(i + batchSize, data.size())); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest batchRequest = + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest.builder() + .vaultId(request.getVaultId()) + .data(new ArrayList<>(batchData)) + .build(); + batches.add(batchRequest); + } + return batches; + } + + public static ErrorRecord createErrorRecord(Map recordMap, int indexNumber, String requestId) { + ErrorRecord err = null; + if (recordMap != null) { + int code = 500; + if (recordMap.containsKey("http_code")) { + code = (Integer) recordMap.get("http_code"); + } else if (recordMap.containsKey("httpCode")) { + code = (Integer) recordMap.get("httpCode"); + } else if (recordMap.containsKey("statusCode")) { + code = (Integer) recordMap.get("statusCode"); + } + String message = recordMap.containsKey("error") ? (String) recordMap.get("error") : + recordMap.containsKey("message") ? (String) recordMap.get("message") : "Unknown error"; + err = new ErrorRecord(indexNumber, message, code, requestId); + } + return err; + } + + public static List handleBulkInsertBatchException( + Throwable ex, List batch, int batchNumber, int batchSize + ) { + List errorRecords = new ArrayList<>(); + Throwable cause = ex.getCause(); + if (cause instanceof ApiClientApiException) { + ApiClientApiException apiException = (ApiClientApiException) cause; + String requestId = extractRequestId(apiException.headers()); + Object rawBody = apiException.body(); + Map responseBody = (rawBody instanceof Map) ? (Map) rawBody : null; + int indexNumber = batchNumber > 0 ? batchNumber * batchSize : 0; + if (responseBody != null) { + if (responseBody.containsKey("records")) { + Object recordss = responseBody.get("records"); + if (recordss instanceof List) { + List recordsList = (List) recordss; + for (Object record : recordsList) { + if (record instanceof Map) { + Map recordMap = (Map) record; + ErrorRecord err = createErrorRecord(recordMap, indexNumber, requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + } else if (responseBody.containsKey("error")) { + Object errField = responseBody.get("error"); + Map recordMap = (errField instanceof Map) ? (Map) errField : null; + String fallbackMsg = (errField instanceof String) ? (String) errField : null; + for (int j = 0; j < batch.size(); j++) { + ErrorRecord err = (recordMap != null) + ? createErrorRecord(recordMap, indexNumber, requestId) + : new ErrorRecord(indexNumber, fallbackMsg != null ? fallbackMsg : apiException.getMessage(), apiException.statusCode(), requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + if (errorRecords.isEmpty()) { + for (int j = 0; j < batch.size(); j++) { + errorRecords.add(new ErrorRecord(indexNumber, apiException.getMessage(), apiException.statusCode(), requestId)); + indexNumber++; + } + } + } else { + int indexNumber = batchNumber > 0 ? batchNumber * batchSize : 0; + for (int j = 0; j < batch.size(); j++) { + ErrorRecord err = new ErrorRecord(indexNumber, ex.getMessage(), 500); + errorRecords.add(err); + indexNumber++; + } + } + return errorRecords; + } + + public static List handleBulkDetokenizeBatchException( + Throwable ex, V1FlowDetokenizeRequest batch, int batchNumber, int batchSize + ) { + List errorRecords = new ArrayList<>(); + Throwable cause = ex.getCause(); + if (cause instanceof ApiClientApiException) { + ApiClientApiException apiException = (ApiClientApiException) cause; + String requestId = extractRequestId(apiException.headers()); + Object rawBody = apiException.body(); + Map responseBody = (rawBody instanceof Map) ? (Map) rawBody : null; + int indexNumber = batchNumber * batchSize; + if (responseBody != null) { + if (responseBody.containsKey("response")) { + Object recordss = responseBody.get("response"); + if (recordss instanceof List) { + List recordsList = (List) recordss; + for (Object record : recordsList) { + if (record instanceof Map) { + Map recordMap = (Map) record; + ErrorRecord err = createErrorRecord(recordMap, indexNumber, requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + } else if (responseBody.containsKey("error")) { + Object errField = responseBody.get("error"); + Map recordMap = (errField instanceof Map) ? (Map) errField : null; + String fallbackMsg = (errField instanceof String) ? (String) errField : null; + int tokenCount = batch.getTokens().isPresent() ? batch.getTokens().get().size() : 0; + for (int j = 0; j < tokenCount; j++) { + ErrorRecord err = (recordMap != null) + ? createErrorRecord(recordMap, indexNumber, requestId) + : new ErrorRecord(indexNumber, fallbackMsg != null ? fallbackMsg : apiException.getMessage(), apiException.statusCode(), requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + if (errorRecords.isEmpty()) { + int tokenCount = batch.getTokens().isPresent() ? batch.getTokens().get().size() : 0; + for (int j = 0; j < tokenCount; j++) { + errorRecords.add(new ErrorRecord(indexNumber, apiException.getMessage(), apiException.statusCode(), requestId)); + indexNumber++; + } + } + } else { + int indexNumber = batchNumber * batchSize; + for (int j = 0; j < batch.getTokens().get().size(); j++) { + ErrorRecord err = new ErrorRecord(indexNumber, ex.getMessage(), 500); + errorRecords.add(err); + indexNumber++; + } + } + return errorRecords; + } + + public static List handleBulkDeleteTokensBatchException( + Throwable ex, + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batch, + int batchNumber, int batchSize + ) { + List errorRecords = new ArrayList<>(); + Throwable cause = ex.getCause(); + if (cause instanceof ApiClientApiException) { + ApiClientApiException apiException = (ApiClientApiException) cause; + String requestId = extractRequestId(apiException.headers()); + Object rawBody = apiException.body(); + Map responseBody = (rawBody instanceof Map) ? (Map) rawBody : null; + int indexNumber = batchNumber * batchSize; + if (responseBody != null) { + if (responseBody.containsKey("tokens")) { + Object tokensList = responseBody.get("tokens"); + if (tokensList instanceof List) { + List recordsList = (List) tokensList; + for (Object record : recordsList) { + if (record instanceof Map) { + Map recordMap = (Map) record; + ErrorRecord err = createErrorRecord(recordMap, indexNumber, requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + } else if (responseBody.containsKey("error")) { + Object errField = responseBody.get("error"); + Map recordMap = (errField instanceof Map) ? (Map) errField : null; + String fallbackMsg = (errField instanceof String) ? (String) errField : null; + int tokenCount = batch.getTokens().isPresent() ? batch.getTokens().get().size() : 0; + for (int j = 0; j < tokenCount; j++) { + ErrorRecord err = (recordMap != null) + ? createErrorRecord(recordMap, indexNumber, requestId) + : new ErrorRecord(indexNumber, fallbackMsg != null ? fallbackMsg : apiException.getMessage(), apiException.statusCode(), requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + if (errorRecords.isEmpty()) { + int tokenCount = batch.getTokens().isPresent() ? batch.getTokens().get().size() : 0; + for (int j = 0; j < tokenCount; j++) { + errorRecords.add(new ErrorRecord(indexNumber, apiException.getMessage(), apiException.statusCode(), requestId)); + indexNumber++; + } + } + } else { + int indexNumber = batchNumber * batchSize; + for (int j = 0; j < batch.getTokens().get().size(); j++) { + ErrorRecord err = new ErrorRecord(indexNumber, ex.getMessage(), 500); + errorRecords.add(err); + indexNumber++; + } + } + return errorRecords; + } + + public static List handleBulkTokenizeBatchException( + Throwable ex, + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest batch, + int batchNumber, int batchSize + ) { + List errorRecords = new ArrayList<>(); + Throwable cause = ex.getCause(); + if (cause instanceof ApiClientApiException) { + ApiClientApiException apiException = (ApiClientApiException) cause; + String requestId = extractRequestId(apiException.headers()); + Object rawBody = apiException.body(); + Map responseBody = (rawBody instanceof Map) ? (Map) rawBody : null; + int indexNumber = batchNumber * batchSize; + if (responseBody != null) { + if (responseBody.containsKey("response")) { + Object responseList = responseBody.get("response"); + if (responseList instanceof List) { + List recordsList = (List) responseList; + for (Object record : recordsList) { + if (record instanceof Map) { + Map recordMap = (Map) record; + ErrorRecord err = createErrorRecord(recordMap, indexNumber, requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + } else if (responseBody.containsKey("error")) { + Object errField = responseBody.get("error"); + Map recordMap = (errField instanceof Map) ? (Map) errField : null; + String fallbackMsg = (errField instanceof String) ? (String) errField : null; + int batchDataSize = batch.getData().isPresent() ? batch.getData().get().size() : 0; + for (int j = 0; j < batchDataSize; j++) { + ErrorRecord err = (recordMap != null) + ? createErrorRecord(recordMap, indexNumber, requestId) + : new ErrorRecord(indexNumber, fallbackMsg != null ? fallbackMsg : apiException.getMessage(), apiException.statusCode(), requestId); + errorRecords.add(err); + indexNumber++; + } + } + } + if (errorRecords.isEmpty()) { + int batchDataSize = batch.getData().isPresent() ? batch.getData().get().size() : 0; + for (int j = 0; j < batchDataSize; j++) { + errorRecords.add(new ErrorRecord(indexNumber, apiException.getMessage(), apiException.statusCode(), requestId)); + indexNumber++; + } + } + } else { + int indexNumber = batchNumber * batchSize; + int batchDataSize = batch.getData().isPresent() ? batch.getData().get().size() : 0; + for (int j = 0; j < batchDataSize; j++) { + ErrorRecord err = new ErrorRecord(indexNumber, ex.getMessage(), 500); + errorRecords.add(err); + indexNumber++; + } + } + return errorRecords; + } + + public static BulkInsertResponse formatBulkInsertResponse(V1InsertResponse response, int batch, int batchSize, Map> headers) { + BulkInsertResponse formattedResponse = null; + List successRecords = new ArrayList<>(); + List errorRecords = new ArrayList<>(); + if (response != null) { + String requestId = extractRequestId(headers); + List record = response.getRecords().get(); + int indexNumber = batch * batchSize; + int recordsSize = response.getRecords().get().size(); + for (int index = 0; index < recordsSize; index++) { + if (record.get(index).getError().isPresent()) { + ErrorRecord errorRecord = new ErrorRecord(indexNumber, record.get(index).getError().get(), record.get(index).getHttpCode().orElse(500), requestId); + errorRecords.add(errorRecord); + } else { + Map> tokensMap = null; + if (record.get(index).getTokens().isPresent()) { + tokensMap = new HashMap<>(); + Map tok = record.get(index).getTokens().get(); + for (Map.Entry entry : tok.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + List tokenList = new ArrayList<>(); + if (value instanceof List) { + List valueList = (List) value; + for (Object item : valueList) { + if (item instanceof Map) { + Map tokenMap = (Map) item; + com.skyflow.vault.data.Token token = new com.skyflow.vault.data.Token((String) tokenMap.get("token"), (String) tokenMap.get("tokenGroupName")); + tokenList.add(token); + } + } + } + tokensMap.put(key, tokenList); + } + } + Success success = new Success(indexNumber, record.get(index).getSkyflowId().orElse(null), tokensMap, record.get(index).getData().isPresent() ? record.get(index).getData().get() : null, record.get(index).getTableName().isPresent() ? record.get(index).getTableName().get() : null); + successRecords.add(success); + } + indexNumber++; + } + formattedResponse = new BulkInsertResponse(successRecords, errorRecords); + } + return formattedResponse; + } + + public static BulkDetokenizeResponse formatBulkDetokenizeResponse(V1FlowDetokenizeResponse response, int batch, int batchSize, Map> headers) { + if (response != null && response.getResponse().isPresent()) { + String requestId = extractRequestId(headers); + List record = response.getResponse().get(); + List errorRecords = new ArrayList<>(); + List successRecords = new ArrayList<>(); + int indexNumber = batch * batchSize; + int recordsSize = record.size(); + for (int index = 0; index < recordsSize; index++) { + if (record.get(index).getError().isPresent()) { + ErrorRecord errorRecord = new ErrorRecord(indexNumber, record.get(index).getError().get(), record.get(index).getHttpCode().orElse(500), requestId); + errorRecords.add(errorRecord); + } else { + DetokenizeResponseObject success = new DetokenizeResponseObject(indexNumber, record.get(index).getToken().orElse(null), record.get(index).getValue().orElse(null), record.get(index).getTokenGroupName().orElse(null), record.get(index).getError().orElse(null), record.get(index).getMetadata().orElse(null)); + successRecords.add(success); + } + indexNumber++; + } + return new BulkDetokenizeResponse(successRecords, errorRecords); + } + return null; + } + + public static BulkDeleteTokensResponse formatBulkDeleteTokensResponse( + V1FlowDeleteTokenResponse response, int batch, int batchSize, Map> headers) { + if (response != null && response.getTokens().isPresent()) { + String requestId = extractRequestId(headers); + List records = response.getTokens().get(); + List errorRecords = new ArrayList<>(); + List successRecords = new ArrayList<>(); + int indexNumber = batch * batchSize; + for (V1DeleteTokenResponseObject record : records) { + String tokenValue = record.getValue().orElse(null); + if (record.getError().isPresent() + && record.getError().get() != null + && !record.getError().get().isEmpty() + && record.getHttpCode().orElse(200) != 200) { + ErrorRecord errorRecord = new ErrorRecord(indexNumber, record.getError().get(), + record.getHttpCode().orElse(500), requestId); + errorRecords.add(errorRecord); + } else { + DeleteTokensSuccess success = new DeleteTokensSuccess(indexNumber, tokenValue); + successRecords.add(success); + } + indexNumber++; + } + return new BulkDeleteTokensResponse(successRecords, errorRecords); + } + return null; + } + + public static BulkTokenizeResponse formatBulkTokenizeResponse( + V1FlowTokenizeResponse response, + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest batchRequest, + int batchNumber, int batchSize, Map> headers) { + if (response != null && response.getResponse().isPresent()) { + String requestId = extractRequestId(headers); + List records = response.getResponse().get(); + List successRecords = new ArrayList<>(); + List errorRecords = new ArrayList<>(); + int indexNumber = batchNumber * batchSize; + for (V1FlowTokenizeResponseObject record : records) { + Object value = record.getValue().orElse(null); + TokenizeSuccess successEntry = null; + if (record.getTokens().isPresent()) { + for (FlowTokenizeResponseObjectToken tokenObj : record.getTokens().get()) { + if (tokenObj.getError().isPresent()) { + errorRecords.add(new ErrorRecord(indexNumber, tokenObj.getError().get(), tokenObj.getHttpCode().orElse(500), requestId)); + } else if (tokenObj.getTokenGroupName().isPresent() && tokenObj.getToken().isPresent()) { + if (successEntry == null) { + successEntry = new TokenizeSuccess(indexNumber, value); + } + successEntry.addToken(tokenObj.getTokenGroupName().get(), tokenObj.getToken().get()); + } + } + } + if (successEntry != null) { + successRecords.add(successEntry); + } + indexNumber++; + } + return new BulkTokenizeResponse(successRecords, errorRecords); + } + return null; + } } diff --git a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java index 98dfdf64..c835cc78 100644 --- a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java @@ -381,4 +381,231 @@ public static void validateTokenizeRequest(TokenizeRequest request) throws Skyfl } } + // ── Bulk (batched/concurrent) request validations ──────────────────────── + + public static void validateBulkInsertRequest(BulkInsertRequest insertRequest) throws SkyflowException { + String table = insertRequest.getTable(); + ArrayList records = insertRequest.getRecords(); + if (records == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.RECORDS_IS_REQUIRED.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.RecordsKeyError.getMessage()); + } else if (records.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_RECORDS.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRecords.getMessage()); + } + + for (BulkInsertRecord record : records) { + if (record == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_RECORD.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidRecord.getMessage()); + } + } + + // table check if specified for both + if (insertRequest.getTable() != null && !table.trim().isEmpty()) { + for (BulkInsertRecord record : records) { + if (record.getTable() != null && !record.getTable().trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TABLE_SPECIFIED_AT_BOTH_PLACE.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TableSpecifiedInRequestAndRecordObject.getMessage()); + } + } + } + // table check if not specified for both or if missing in any object + if (insertRequest.getTable() == null || table.trim().isEmpty()) { + for (BulkInsertRecord record : records) { + if (record.getTable() == null || record.getTable().trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TABLE_NOT_SPECIFIED_AT_BOTH_PLACE.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TableNotSpecifiedInRequestAndRecordObject.getMessage()); + } + } + } + // upsert check 1 + if (insertRequest.getTable() != null && !table.trim().isEmpty()) { + for (BulkInsertRecord record : records) { + if (record.getUpsert() != null && record.getUpsert().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_UPSERT_VALUES.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyUpsertValues.getMessage()); + } + if (record.getUpsert() != null && !record.getUpsert().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.UPSERT_TABLE_REQUEST_AT_RECORD_LEVEL.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.UpsertTableRequestAtRecordLevel.getMessage()); + } + } + } + // upsert check 2 + if (insertRequest.getTable() == null || table.trim().isEmpty()) { + if (insertRequest.getUpsert() != null && !insertRequest.getUpsert().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.UPSERT_TABLE_REQUEST_AT_REQUEST_LEVEL.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.UpsertTableRequestAtRequestLevel.getMessage()); + } + } + + if (insertRequest.getUpsert() != null && insertRequest.getUpsert().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_UPSERT_VALUES.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyUpsertValues.getMessage()); + } + + for (BulkInsertRecord record : records) { + if (record.getData() != null) { + for (String key : record.getData().keySet()) { + if (key == null || key.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_KEY_IN_VALUES.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyKeyInRecords.getMessage()); + } else { + Object value = record.getData().get(key); + if (value == null || value.toString().trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_VALUE_IN_VALUES.getLog(), + InterfaceName.INSERT.getName(), key + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyValueInValues.getMessage()); + } + } + } + } + } + } + + public static void validateBulkDetokenizeRequest(BulkDetokenizeRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.DETOKENIZE_REQUEST_NULL.getLog(), InterfaceName.DETOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.DetokenizeRequestNull.getMessage()); + } + List tokens = request.getTokens(); + if (tokens == null || tokens.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_DETOKENIZE_DATA.getLog(), InterfaceName.DETOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDetokenizeData.getMessage()); + } + + for (int index = 0; index < tokens.size(); index++) { + String token = tokens.get(index); + if (token == null || token.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_DETOKENIZE_DATA.getLog(), + InterfaceName.DETOKENIZE.getName(), + String.valueOf(index))); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenInDetokenizeData.getMessage()); + } + } + + List groupRedactions = request.getTokenGroupRedactions(); + if (groupRedactions != null && !groupRedactions.isEmpty()) { + for (BulkTokenGroupRedactions group : groupRedactions) { + if (group == null) { + LogUtil.printErrorLog(Utils.parameterizedString(ErrorLogs.NULL_TOKEN_REDACTION_GROUP_OBJECT.getLog(), InterfaceName.DETOKENIZE.getName())); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullTokenGroupRedactions.getMessage()); + } + String groupName = group.getTokenGroupName(); + String redaction = group.getRedaction(); + if (groupName == null || groupName.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString(ErrorLogs.NULL_TOKEN_GROUP_NAME_IN_TOKEN_GROUP.getLog(), InterfaceName.DETOKENIZE.getName())); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullTokenGroupNameInTokenGroup.getMessage()); + } + if (redaction == null || redaction.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString(ErrorLogs.EMPTY_OR_NULL_REDACTION_IN_TOKEN_GROUP.getLog(), InterfaceName.DETOKENIZE.getName())); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullRedactionInTokenGroup.getMessage()); + } + } + } + } + + public static void validateBulkDeleteTokensRequest(BulkDeleteTokensRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.DELETE_TOKENS_REQUEST_NULL.getLog(), InterfaceName.DELETE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.DeleteTokensRequestNull.getMessage()); + } + List tokens = request.getTokens(); + if (tokens == null || tokens.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_DELETE_TOKENS_DATA.getLog(), InterfaceName.DELETE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyDeleteTokensData.getMessage()); + } + + for (int index = 0; index < tokens.size(); index++) { + String token = tokens.get(index); + if (token == null || token.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_TOKEN_IN_DELETE_TOKENS_DATA.getLog(), + InterfaceName.DELETE.getName(), + String.valueOf(index))); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenInDeleteTokensData.getMessage()); + } + } + } + + public static void validateBulkTokenizeRequest(BulkTokenizeRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TOKENIZE_REQUEST_NULL.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TokenizeRequestNull.getMessage()); + } + List data = request.getData(); + if (data == null || data.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_TOKENIZE_DATA.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenizeData.getMessage()); + } + for (int i = 0; i < data.size(); i++) { + BulkTokenizeRecord record = data.get(i); + if (record == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TOKENIZE_RECORD_NULL.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TokenizeRecordNull.getMessage()); + } + Object value = record.getValue(); + boolean isInvalid = value == null + || (value instanceof String && ((String) value).trim().isEmpty()); + if (isInvalid) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_VALUE_IN_TOKENIZE_RECORD.getLog(), InterfaceName.TOKENIZE.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyValueInTokenizeRecord.getMessage()); + } + List tokenGroupNames = record.getTokenGroupNames(); + if (tokenGroupNames != null) { + for (int j = 0; j < tokenGroupNames.size(); j++) { + String groupName = tokenGroupNames.get(j); + if (groupName == null || groupName.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_TOKEN_GROUP_NAME_IN_TOKENIZE_RECORD.getLog(), + InterfaceName.TOKENIZE.getName(), + String.valueOf(j) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenGroupNameInTokenizeRecord.getMessage()); + } + } + } + } + } + } diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java index 28c29839..bf6abc42 100644 --- a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -14,14 +14,27 @@ import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; +import com.skyflow.generated.rest.types.V1InsertRecordData; import com.skyflow.generated.rest.types.V1InsertResponse; +import com.skyflow.generated.rest.types.V1Upsert; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; +import com.skyflow.logs.WarningLogs; import com.skyflow.utils.Constants; import com.skyflow.utils.Utils; import com.skyflow.utils.logger.LogUtil; import com.skyflow.utils.validations.Validations; import com.skyflow.vault.data.*; +import io.github.cdimascio.dotenv.Dotenv; +import io.github.cdimascio.dotenv.DotenvException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import static com.skyflow.utils.Utils.*; @@ -33,21 +46,46 @@ public final class VaultController extends VaultClient public VaultController(VaultConfig vaultConfig, Credentials credentials) throws SkyflowException { super(vaultConfig, credentials); } - private RequestOptions buildRequestOptions() { + + /** + * Immutable per-call batch size / concurrency limit. Computed fresh on every bulk call + * instead of being stored on instance fields, since a VaultController instance is cached + * and reused (see Skyflow#vaultClientsMap) and may be invoked concurrently from multiple + * threads. + */ + private static final class BatchConfig { + final int batchSize; + final int concurrencyLimit; + + BatchConfig(int batchSize, int concurrencyLimit) { + this.batchSize = batchSize; + this.concurrencyLimit = concurrencyLimit; + } + } + + private RequestOptions buildRequestOptions(RequestContext context) { RequestOptions.Builder builder = RequestOptions.builder() .addHeader(Constants.SDK_METRICS_HEADER_KEY, metrics.toString()); + context.getHeaders().forEach((k, v) -> builder.addHeader(k.toString(), v)); return builder.build(); } @Override public InsertResponse insert(InsertRequest request) throws SkyflowException { + return insert(request, null); + } + + public InsertResponse insert(InsertRequest request, InsertOptions options) throws SkyflowException { try { LogUtil.printInfoLog(InfoLogs.INSERT_TRIGGERED.getLog()); LogUtil.printInfoLog(InfoLogs.VALIDATE_INSERT_REQUEST.getLog()); Validations.validateInsertRequest(request); setBearerToken(); V1InsertRequest insertRequest = getBulkInsertRequestBody(request, super.getVaultConfig()); - V1InsertResponse response = this.getRecordsApi().withRawResponse().insert(insertRequest, buildRequestOptions()).body(); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("INSERT"); + if (interceptor != null) interceptor.intercept(ctx); + V1InsertResponse response = this.getRecordsApi().withRawResponse().insert(insertRequest, buildRequestOptions(ctx)).body(); return buildInsertResponse(response); } catch (ApiClientApiException e) { String bodyString = gson.toJson(e.body()); @@ -61,6 +99,10 @@ public InsertResponse insert(InsertRequest request) throws SkyflowException { @Override public DetokenizeResponse detokenize(DetokenizeRequest request) throws SkyflowException { + return detokenize(request, null); + } + + public DetokenizeResponse detokenize(DetokenizeRequest request, DetokenizeOptions options) throws SkyflowException { try { LogUtil.printInfoLog(InfoLogs.DETOKENIZE_TRIGGERED.getLog()); LogUtil.printInfoLog(InfoLogs.VALIDATE_DETOKENIZE_REQUEST.getLog()); @@ -68,7 +110,10 @@ public DetokenizeResponse detokenize(DetokenizeRequest request) throws SkyflowEx setBearerToken(); com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest requestDetokenize = getDetokenizeRequestBody(request, this.getVaultConfig().getVaultId()); - com.skyflow.generated.rest.types.V1FlowDetokenizeResponse response = this.getRecordsApi().withRawResponse().detokenize(requestDetokenize, buildRequestOptions()).body(); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("DETOKENIZE"); + if (interceptor != null) interceptor.intercept(ctx); + com.skyflow.generated.rest.types.V1FlowDetokenizeResponse response = this.getRecordsApi().withRawResponse().detokenize(requestDetokenize, buildRequestOptions(ctx)).body(); return buildDetokenizeResponse(response); } catch (ApiClientApiException e) { @@ -82,6 +127,10 @@ public DetokenizeResponse detokenize(DetokenizeRequest request) throws SkyflowEx } public TokenizeResponse tokenize(TokenizeRequest request) throws SkyflowException { + return tokenize(request, null); + } + + public TokenizeResponse tokenize(TokenizeRequest request, TokenizeOptions options) throws SkyflowException { try { LogUtil.printInfoLog(InfoLogs.TOKENIZE_TRIGGERED.getLog()); LogUtil.printInfoLog(InfoLogs.VALIDATING_TOKENIZE_REQUEST.getLog()); @@ -89,7 +138,10 @@ public TokenizeResponse tokenize(TokenizeRequest request) throws SkyflowExceptio setBearerToken(); com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest requestTokenize = getTokenizeRequestBody(request, this.getVaultConfig().getVaultId()); - ApiClientHttpResponse response = this.getRecordsApi().withRawResponse().tokenize(requestTokenize, buildRequestOptions()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("TOKENIZE"); + if (interceptor != null) interceptor.intercept(ctx); + ApiClientHttpResponse response = this.getRecordsApi().withRawResponse().tokenize(requestTokenize, buildRequestOptions(ctx)); LogUtil.printInfoLog(InfoLogs.TOKENIZE_REQUEST_RESOLVED.getLog()); TokenizeResponse tokenizeResponse = buildTokenizeResponse(response.body(), response.headers(), request.getData().size()); @@ -106,6 +158,10 @@ public TokenizeResponse tokenize(TokenizeRequest request) throws SkyflowExceptio } public DeleteTokensResponse deleteTokens(DeleteTokensRequest request) throws SkyflowException { + return deleteTokens(request, null); + } + + public DeleteTokensResponse deleteTokens(DeleteTokensRequest request, DeleteTokensOptions options) throws SkyflowException { try { LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_TRIGGERED.getLog()); LogUtil.printInfoLog(InfoLogs.VALIDATE_DELETE_TOKENS_REQUEST.getLog()); @@ -113,7 +169,10 @@ public DeleteTokensResponse deleteTokens(DeleteTokensRequest request) throws Sky setBearerToken(); com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest requestDeleteTokens = getDeleteTokensRequestBody(request, this.getVaultConfig().getVaultId()); - ApiClientHttpResponse response = this.getRecordsApi().withRawResponse().deletetoken(requestDeleteTokens, buildRequestOptions()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("DELETE_TOKENS"); + if (interceptor != null) interceptor.intercept(ctx); + ApiClientHttpResponse response = this.getRecordsApi().withRawResponse().deletetoken(requestDeleteTokens, buildRequestOptions(ctx)); LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_REQUEST_RESOLVED.getLog()); DeleteTokensResponse deleteTokensResponse = buildDeleteTokensResponse(response.body(), response.headers(), request.getTokens().size()); @@ -129,5 +188,918 @@ public DeleteTokensResponse deleteTokens(DeleteTokensRequest request) throws Sky } } + // ── Bulk Insert ─────────────────────────────────────────────────────────── + + public BulkInsertResponse bulkInsert(BulkInsertRequest insertRequest) throws SkyflowException { + return bulkInsert(insertRequest, null); + } + + public BulkInsertResponse bulkInsert(BulkInsertRequest insertRequest, InsertOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.INSERT_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_INSERT_REQUEST.getLog()); + Validations.validateBulkInsertRequest(insertRequest); + BatchConfig cfg = configureInsertConcurrencyAndBatchSize(insertRequest.getRecords().size()); + + setBearerToken(); + V1InsertRequest request = Utils.getBulkInsertRequestBody(insertRequest, this.getVaultConfig()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + return this.processBulkInsertSync(request, insertRequest.getRecords(), interceptor, cfg); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } catch (ExecutionException e) { + LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); + Throwable cause = e.getCause(); + throw new SkyflowException(cause != null && cause.getMessage() != null ? cause.getMessage() : e.getMessage()); + } + } + + public CompletableFuture bulkInsertAsync(BulkInsertRequest insertRequest) throws SkyflowException { + return bulkInsertAsync(insertRequest, null); + } + + public CompletableFuture bulkInsertAsync(BulkInsertRequest insertRequest, InsertOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.INSERT_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_INSERT_REQUEST.getLog()); + Validations.validateBulkInsertRequest(insertRequest); + BatchConfig cfg = configureInsertConcurrencyAndBatchSize(insertRequest.getRecords().size()); + + setBearerToken(); + V1InsertRequest request = Utils.getBulkInsertRequestBody(insertRequest, this.getVaultConfig()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + List errorRecords = Collections.synchronizedList(new ArrayList<>()); + List> futures = this.insertBatchFutures(request, errorRecords, interceptor, cfg); + + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> { + List successRecords = new ArrayList<>(); + + for (CompletableFuture future : futures) { + BulkInsertResponse futureResponse = future.join(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successRecords.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorRecords.addAll(futureResponse.getErrors()); + } + } + } + + return new BulkInsertResponse(successRecords, errorRecords, insertRequest.getRecords()); + }); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } + } + + // ── Bulk Detokenize ─────────────────────────────────────────────────────── + + public BulkDetokenizeResponse bulkDetokenize(BulkDetokenizeRequest detokenizeRequest) throws SkyflowException { + return bulkDetokenize(detokenizeRequest, null); + } + + public BulkDetokenizeResponse bulkDetokenize(BulkDetokenizeRequest detokenizeRequest, DetokenizeOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.DETOKENIZE_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_DETOKENIZE_REQUEST.getLog()); + Validations.validateBulkDetokenizeRequest(detokenizeRequest); + BatchConfig cfg = configureDetokenizeConcurrencyAndBatchSize(detokenizeRequest.getTokens().size()); + setBearerToken(); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest request = + Utils.getBulkDetokenizeRequestBody(detokenizeRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + return this.processBulkDetokenizeSync(request, detokenizeRequest.getTokens(), interceptor, cfg); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new SkyflowException(e.getMessage()); + } catch (ExecutionException e) { + throw new SkyflowException(e.getMessage()); + } + } + + public CompletableFuture bulkDetokenizeAsync(BulkDetokenizeRequest detokenizeRequest) throws SkyflowException { + return bulkDetokenizeAsync(detokenizeRequest, null); + } + + public CompletableFuture bulkDetokenizeAsync(BulkDetokenizeRequest detokenizeRequest, DetokenizeOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.DETOKENIZE_TRIGGERED.getLog()); + ExecutorService executor = null; + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_DETOKENIZE_REQUEST.getLog()); + Validations.validateBulkDetokenizeRequest(detokenizeRequest); + BatchConfig cfg = configureDetokenizeConcurrencyAndBatchSize(detokenizeRequest.getTokens().size()); + setBearerToken(); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest request = + Utils.getBulkDetokenizeRequestBody(detokenizeRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + + LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); + + List errorTokens = Collections.synchronizedList(new ArrayList<>()); + List successRecords = new ArrayList<>(); + + List batches = + Utils.createBulkDetokenizeBatches(request, cfg.batchSize); + + executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); + List> futures = this.detokenizeBatchFutures(executor, batches, errorTokens, interceptor, cfg.batchSize); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> { + for (CompletableFuture future : futures) { + BulkDetokenizeResponse futureResponse = future.join(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successRecords.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorTokens.addAll(futureResponse.getErrors()); + } + } + } + LogUtil.printInfoLog(InfoLogs.DETOKENIZE_REQUEST_RESOLVED.getLog()); + return new BulkDetokenizeResponse(successRecords, errorTokens, detokenizeRequest.getTokens()); + }); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (SkyflowException e) { + LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); + throw e; + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } finally { + if (executor != null) executor.shutdown(); + } + } + + // ── Bulk Delete Tokens ──────────────────────────────────────────────────── + + public BulkDeleteTokensResponse bulkDeleteTokens(BulkDeleteTokensRequest deleteTokensRequest) throws SkyflowException { + return bulkDeleteTokens(deleteTokensRequest, null); + } + + public BulkDeleteTokensResponse bulkDeleteTokens(BulkDeleteTokensRequest deleteTokensRequest, DeleteTokensOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_DELETE_TOKENS_REQUEST.getLog()); + Validations.validateBulkDeleteTokensRequest(deleteTokensRequest); + BatchConfig cfg = configureDeleteTokensConcurrencyAndBatchSize(deleteTokensRequest.getTokens().size()); + setBearerToken(); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest request = + Utils.getBulkDeleteTokensRequestBody(deleteTokensRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + return this.processBulkDeleteTokensSync(request, deleteTokensRequest.getTokens(), interceptor, cfg); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ExecutionException | InterruptedException e) { + LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } + } + + public CompletableFuture bulkDeleteTokensAsync(BulkDeleteTokensRequest deleteTokensRequest) throws SkyflowException { + return bulkDeleteTokensAsync(deleteTokensRequest, null); + } + + public CompletableFuture bulkDeleteTokensAsync(BulkDeleteTokensRequest deleteTokensRequest, DeleteTokensOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_TRIGGERED.getLog()); + ExecutorService executor = null; + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_DELETE_TOKENS_REQUEST.getLog()); + Validations.validateBulkDeleteTokensRequest(deleteTokensRequest); + BatchConfig cfg = configureDeleteTokensConcurrencyAndBatchSize(deleteTokensRequest.getTokens().size()); + setBearerToken(); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest request = + Utils.getBulkDeleteTokensRequestBody(deleteTokensRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + + LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); + + List errorTokens = Collections.synchronizedList(new ArrayList<>()); + List successRecords = Collections.synchronizedList(new ArrayList<>()); + + List batches = + Utils.createBulkDeleteTokensBatches(request, cfg.batchSize); + + executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); + List> futures = + this.deleteTokensBatchFutures(executor, batches, interceptor, cfg.batchSize); + + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> { + for (CompletableFuture future : futures) { + BulkDeleteTokensResponse futureResponse = future.join(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successRecords.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorTokens.addAll(futureResponse.getErrors()); + } + } + } + LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_REQUEST_RESOLVED.getLog()); + return new BulkDeleteTokensResponse(successRecords, errorTokens, deleteTokensRequest.getTokens()); + }); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (SkyflowException e) { + LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); + throw e; + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } finally { + if (executor != null) executor.shutdown(); + } + } + + // ── Bulk Tokenize ───────────────────────────────────────────────────────── + + public BulkTokenizeResponse bulkTokenize(BulkTokenizeRequest tokenizeRequest) throws SkyflowException { + return bulkTokenize(tokenizeRequest, null); + } + + public BulkTokenizeResponse bulkTokenize(BulkTokenizeRequest tokenizeRequest, TokenizeOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.TOKENIZE_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATING_TOKENIZE_REQUEST.getLog()); + Validations.validateBulkTokenizeRequest(tokenizeRequest); + BatchConfig cfg = configureTokenizeConcurrencyAndBatchSize(tokenizeRequest.getData().size()); + setBearerToken(); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest request = + Utils.getBulkTokenizeRequestBody(tokenizeRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + return this.processBulkTokenizeSync(request, tokenizeRequest.getData(), interceptor, cfg); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (SkyflowException e) { + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw e; + } catch (ExecutionException | InterruptedException e) { + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } + } + + public CompletableFuture bulkTokenizeAsync(BulkTokenizeRequest tokenizeRequest) throws SkyflowException { + return bulkTokenizeAsync(tokenizeRequest, null); + } + + public CompletableFuture bulkTokenizeAsync(BulkTokenizeRequest tokenizeRequest, TokenizeOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.TOKENIZE_TRIGGERED.getLog()); + ExecutorService executor = null; + try { + LogUtil.printInfoLog(InfoLogs.VALIDATING_TOKENIZE_REQUEST.getLog()); + Validations.validateBulkTokenizeRequest(tokenizeRequest); + BatchConfig cfg = configureTokenizeConcurrencyAndBatchSize(tokenizeRequest.getData().size()); + setBearerToken(); + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest request = + Utils.getBulkTokenizeRequestBody(tokenizeRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + + LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); + + List errorRecords = Collections.synchronizedList(new ArrayList<>()); + List successRecords = Collections.synchronizedList(new ArrayList<>()); + + List batches = + Utils.createBulkTokenizeBatches(request, cfg.batchSize); + + executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); + List> futures = + this.tokenizeBatchFutures(executor, batches, interceptor, cfg.batchSize); + + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> { + for (CompletableFuture future : futures) { + BulkTokenizeResponse futureResponse = future.join(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successRecords.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorRecords.addAll(futureResponse.getErrors()); + } + } + } + LogUtil.printInfoLog(InfoLogs.TOKENIZE_REQUEST_RESOLVED.getLog()); + return new BulkTokenizeResponse(successRecords, errorRecords, tokenizeRequest.getData()); + }); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (SkyflowException e) { + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw e; + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } finally { + if (executor != null) executor.shutdown(); + } + } + + // ── Bulk private helpers ────────────────────────────────────────────────── + + private BulkDeleteTokensResponse processBulkDeleteTokensSync( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest deleteTokensRequest, + List originalTokens, + RequestInterceptor interceptor, + BatchConfig cfg + ) throws ExecutionException, InterruptedException, SkyflowException { + LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); + List errorRecords = Collections.synchronizedList(new ArrayList<>()); + List successRecords = new ArrayList<>(); + ExecutorService executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); + List batches = + Utils.createBulkDeleteTokensBatches(deleteTokensRequest, cfg.batchSize); + try { + List> futures = + this.deleteTokensBatchFutures(executor, batches, interceptor, cfg.batchSize); + try { + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(); + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); + } + for (CompletableFuture future : futures) { + BulkDeleteTokensResponse futureResponse = future.get(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) successRecords.addAll(futureResponse.getSuccess()); + if (futureResponse.getErrors() != null) errorRecords.addAll(futureResponse.getErrors()); + } + } + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } finally { + executor.shutdown(); + } + BulkDeleteTokensResponse response = new BulkDeleteTokensResponse(successRecords, errorRecords, originalTokens); + LogUtil.printInfoLog(InfoLogs.DELETE_TOKENS_REQUEST_RESOLVED.getLog()); + return response; + } + + private List> deleteTokensBatchFutures( + ExecutorService executor, + List batches, + RequestInterceptor interceptor, + int batchSize) { + List> futures = new ArrayList<>(); + if (batches == null) return futures; + for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { + final int index = batchIndex; + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batch = batches.get(index); + RequestContext ctx = new RequestContext("DELETE_TOKENS"); + if (interceptor != null) interceptor.intercept(ctx); + CompletableFuture future = CompletableFuture + .supplyAsync(() -> processDeleteTokensBatch(batch, ctx), executor) + .handle((result, ex) -> { + if (ex != null) { + List batchErrors = + Utils.handleBulkDeleteTokensBatchException(ex, batch, index, batchSize); + return new BulkDeleteTokensResponse(new ArrayList<>(), batchErrors); + } + return Utils.formatBulkDeleteTokensResponse(result.body(), index, batchSize, result.headers()); + }); + futures.add(future); + } + return futures; + } + + private ApiClientHttpResponse processDeleteTokensBatch( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batch, + RequestContext ctx) { + return this.getRecordsApi().withRawResponse().deletetoken(batch, buildRequestOptions(ctx)); + } + + private BatchConfig configureDeleteTokensConcurrencyAndBatchSize(int totalRequests) { + int batchSize = Constants.DELETE_TOKENS_BATCH_SIZE; + int concurrencyLimit; + try { + String userProvidedBatchSize = System.getenv("DELETE_TOKENS_BATCH_SIZE"); + String userProvidedConcurrencyLimit = System.getenv("DELETE_TOKENS_CONCURRENCY_LIMIT"); + + Dotenv dotenv = null; + try { + dotenv = Dotenv.load(); + } catch (DotenvException ignored) {} + + if (userProvidedBatchSize == null && dotenv != null) { + userProvidedBatchSize = dotenv.get("DELETE_TOKENS_BATCH_SIZE"); + } + if (userProvidedConcurrencyLimit == null && dotenv != null) { + userProvidedConcurrencyLimit = dotenv.get("DELETE_TOKENS_CONCURRENCY_LIMIT"); + } + + if (userProvidedBatchSize != null) { + try { + int parsedBatchSize = Integer.parseInt(userProvidedBatchSize); + if (parsedBatchSize > Constants.MAX_DELETE_TOKENS_BATCH_SIZE) { + LogUtil.printWarningLog(WarningLogs.BATCH_SIZE_EXCEEDS_MAX_LIMIT.getLog()); + } + int maxBatchSize = Math.min(parsedBatchSize, Constants.MAX_DELETE_TOKENS_BATCH_SIZE); + if (maxBatchSize > 0) { + batchSize = maxBatchSize; + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.DELETE_TOKENS_BATCH_SIZE; + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.DELETE_TOKENS_BATCH_SIZE; + } + } + + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + + if (userProvidedConcurrencyLimit != null) { + try { + int parsedConcurrencyLimit = Integer.parseInt(userProvidedConcurrencyLimit); + if (parsedConcurrencyLimit > Constants.MAX_DELETE_TOKENS_CONCURRENCY_LIMIT) { + LogUtil.printWarningLog(WarningLogs.CONCURRENCY_EXCEEDS_MAX_LIMIT.getLog()); + } + int maxConcurrencyLimit = Math.min(parsedConcurrencyLimit, Constants.MAX_DELETE_TOKENS_CONCURRENCY_LIMIT); + if (maxConcurrencyLimit > 0) { + concurrencyLimit = Math.min(maxConcurrencyLimit, maxConcurrencyNeeded); + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.DELETE_TOKENS_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.DELETE_TOKENS_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } else { + concurrencyLimit = Math.min(Constants.DELETE_TOKENS_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (Exception e) { + batchSize = Constants.DELETE_TOKENS_BATCH_SIZE; + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + concurrencyLimit = Math.min(Constants.DELETE_TOKENS_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + return new BatchConfig(batchSize, concurrencyLimit); + } + + private BulkTokenizeResponse processBulkTokenizeSync( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest tokenizeRequest, + ArrayList originalData, + RequestInterceptor interceptor, + BatchConfig cfg + ) throws ExecutionException, InterruptedException, SkyflowException { + LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); + List errorRecords = Collections.synchronizedList(new ArrayList<>()); + List successRecords = new ArrayList<>(); + ExecutorService executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); + List batches = + Utils.createBulkTokenizeBatches(tokenizeRequest, cfg.batchSize); + try { + List> futures = + this.tokenizeBatchFutures(executor, batches, interceptor, cfg.batchSize); + try { + CompletableFuture allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + allFutures.join(); + } catch (Exception e) { + // individual batch errors are already captured + } + for (CompletableFuture future : futures) { + BulkTokenizeResponse futureResponse = future.get(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successRecords.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorRecords.addAll(futureResponse.getErrors()); + } + } + } + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } finally { + executor.shutdown(); + } + BulkTokenizeResponse response = new BulkTokenizeResponse(successRecords, errorRecords, originalData); + LogUtil.printInfoLog(InfoLogs.TOKENIZE_REQUEST_RESOLVED.getLog()); + return response; + } + + private List> tokenizeBatchFutures( + ExecutorService executor, + List batches, + RequestInterceptor interceptor, + int batchSize) { + List> futures = new ArrayList<>(); + if (batches == null) return futures; + for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { + final int index = batchIndex; + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest batch = batches.get(index); + RequestContext ctx = new RequestContext("TOKENIZE"); + if (interceptor != null) interceptor.intercept(ctx); + CompletableFuture future = CompletableFuture + .supplyAsync(() -> processTokenizeBatch(batch, ctx), executor) + .handle((result, ex) -> { + if (ex != null) { + List batchErrors = + Utils.handleBulkTokenizeBatchException(ex, batch, index, batchSize); + return new BulkTokenizeResponse(new ArrayList<>(), batchErrors); + } + return Utils.formatBulkTokenizeResponse(result.body(), batch, index, batchSize, result.headers()); + }); + futures.add(future); + } + return futures; + } + + private ApiClientHttpResponse processTokenizeBatch( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest batch, + RequestContext ctx) { + return this.getRecordsApi().withRawResponse().tokenize(batch, buildRequestOptions(ctx)); + } + + private BatchConfig configureTokenizeConcurrencyAndBatchSize(int totalRequests) { + int batchSize = Constants.TOKENIZE_BATCH_SIZE; + int concurrencyLimit; + try { + String userProvidedBatchSize = System.getenv("TOKENIZE_BATCH_SIZE"); + String userProvidedConcurrencyLimit = System.getenv("TOKENIZE_CONCURRENCY_LIMIT"); + + Dotenv dotenv = null; + try { + dotenv = Dotenv.load(); + } catch (DotenvException ignored) {} + + if (userProvidedBatchSize == null && dotenv != null) { + userProvidedBatchSize = dotenv.get("TOKENIZE_BATCH_SIZE"); + } + if (userProvidedConcurrencyLimit == null && dotenv != null) { + userProvidedConcurrencyLimit = dotenv.get("TOKENIZE_CONCURRENCY_LIMIT"); + } + + if (userProvidedBatchSize != null) { + try { + int parsedBatchSize = Integer.parseInt(userProvidedBatchSize); + if (parsedBatchSize > Constants.MAX_TOKENIZE_BATCH_SIZE) { + LogUtil.printWarningLog(WarningLogs.BATCH_SIZE_EXCEEDS_MAX_LIMIT.getLog()); + } + int maxBatchSize = Math.min(parsedBatchSize, Constants.MAX_TOKENIZE_BATCH_SIZE); + if (maxBatchSize > 0) { + batchSize = maxBatchSize; + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.TOKENIZE_BATCH_SIZE; + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.TOKENIZE_BATCH_SIZE; + } + } + + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + + if (userProvidedConcurrencyLimit != null) { + try { + int parsedConcurrencyLimit = Integer.parseInt(userProvidedConcurrencyLimit); + if (parsedConcurrencyLimit > Constants.MAX_TOKENIZE_CONCURRENCY_LIMIT) { + LogUtil.printWarningLog(WarningLogs.CONCURRENCY_EXCEEDS_MAX_LIMIT.getLog()); + } + int maxConcurrencyLimit = Math.min(parsedConcurrencyLimit, Constants.MAX_TOKENIZE_CONCURRENCY_LIMIT); + if (maxConcurrencyLimit > 0) { + concurrencyLimit = Math.min(maxConcurrencyLimit, maxConcurrencyNeeded); + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.TOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.TOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } else { + concurrencyLimit = Math.min(Constants.TOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (Exception e) { + batchSize = Constants.TOKENIZE_BATCH_SIZE; + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + concurrencyLimit = Math.min(Constants.TOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + return new BatchConfig(batchSize, concurrencyLimit); + } + + private BatchConfig configureDetokenizeConcurrencyAndBatchSize(int totalRequests) { + int batchSize = Constants.DETOKENIZE_BATCH_SIZE; + int concurrencyLimit; + try { + String userProvidedBatchSize = System.getenv("DETOKENIZE_BATCH_SIZE"); + String userProvidedConcurrencyLimit = System.getenv("DETOKENIZE_CONCURRENCY_LIMIT"); + + Dotenv dotenv = null; + try { + dotenv = Dotenv.load(); + } catch (DotenvException ignored) { + // ignore the case if .env file is not found + } + + if (userProvidedBatchSize == null && dotenv != null) { + userProvidedBatchSize = dotenv.get("DETOKENIZE_BATCH_SIZE"); + } + if (userProvidedConcurrencyLimit == null && dotenv != null) { + userProvidedConcurrencyLimit = dotenv.get("DETOKENIZE_CONCURRENCY_LIMIT"); + } + + if (userProvidedBatchSize != null) { + try { + int parsedBatchSize = Integer.parseInt(userProvidedBatchSize); + if (parsedBatchSize > Constants.MAX_DETOKENIZE_BATCH_SIZE) { + LogUtil.printWarningLog(WarningLogs.BATCH_SIZE_EXCEEDS_MAX_LIMIT.getLog()); + } + int maxBatchSize = Math.min(parsedBatchSize, Constants.MAX_DETOKENIZE_BATCH_SIZE); + if (maxBatchSize > 0) { + batchSize = maxBatchSize; + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.DETOKENIZE_BATCH_SIZE; + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.DETOKENIZE_BATCH_SIZE; + } + } + + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + + if (userProvidedConcurrencyLimit != null) { + try { + int parsedConcurrencyLimit = Integer.parseInt(userProvidedConcurrencyLimit); + if (parsedConcurrencyLimit > Constants.MAX_DETOKENIZE_CONCURRENCY_LIMIT) { + LogUtil.printWarningLog(WarningLogs.CONCURRENCY_EXCEEDS_MAX_LIMIT.getLog()); + } + int maxConcurrencyLimit = Math.min(parsedConcurrencyLimit, Constants.MAX_DETOKENIZE_CONCURRENCY_LIMIT); + + if (maxConcurrencyLimit > 0) { + concurrencyLimit = Math.min(maxConcurrencyLimit, maxConcurrencyNeeded); + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.DETOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.DETOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } else { + concurrencyLimit = Math.min(Constants.DETOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (Exception e) { + batchSize = Constants.DETOKENIZE_BATCH_SIZE; + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + concurrencyLimit = Math.min(Constants.DETOKENIZE_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + return new BatchConfig(batchSize, concurrencyLimit); + } + + private BulkInsertResponse processBulkInsertSync( + V1InsertRequest insertRequest, + ArrayList originalPayload, + RequestInterceptor interceptor, + BatchConfig cfg + ) throws ExecutionException, InterruptedException { + LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); + List successRecords = new ArrayList<>(); + List errorRecords = Collections.synchronizedList(new ArrayList<>()); + List> futures = this.insertBatchFutures(insertRequest, errorRecords, interceptor, cfg); + + CompletableFuture allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + allFutures.join(); + + for (CompletableFuture future : futures) { + BulkInsertResponse futureResponse = future.get(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successRecords.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorRecords.addAll(futureResponse.getErrors()); + } + } + } + BulkInsertResponse response = new BulkInsertResponse(successRecords, errorRecords, originalPayload); + LogUtil.printInfoLog(InfoLogs.INSERT_REQUEST_RESOLVED.getLog()); + return response; + } + + private BulkDetokenizeResponse processBulkDetokenizeSync( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest detokenizeRequest, + List originalTokens, + RequestInterceptor interceptor, + BatchConfig cfg + ) throws ExecutionException, InterruptedException, SkyflowException { + LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); + List errorTokens = Collections.synchronizedList(new ArrayList<>()); + List successTokens = new ArrayList<>(); + ExecutorService executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); + List batches = + Utils.createBulkDetokenizeBatches(detokenizeRequest, cfg.batchSize); + try { + List> futures = this.detokenizeBatchFutures(executor, batches, errorTokens, interceptor, cfg.batchSize); + try { + CompletableFuture allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + allFutures.join(); + } catch (Exception e) { + // individual batch errors are already captured + } + for (CompletableFuture future : futures) { + BulkDetokenizeResponse futureResponse = future.get(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successTokens.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorTokens.addAll(futureResponse.getErrors()); + } + } + } + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } finally { + executor.shutdown(); + } + BulkDetokenizeResponse response = new BulkDetokenizeResponse(successTokens, errorTokens, originalTokens); + LogUtil.printInfoLog(InfoLogs.DETOKENIZE_REQUEST_RESOLVED.getLog()); + return response; + } + + private List> detokenizeBatchFutures( + ExecutorService executor, + List batches, + List errorTokens, + RequestInterceptor interceptor, + int batchSize) { + List> futures = new ArrayList<>(); + try { + for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest batch = batches.get(batchIndex); + int batchNumber = batchIndex; + RequestContext ctx = new RequestContext("DETOKENIZE"); + if (interceptor != null) interceptor.intercept(ctx); + CompletableFuture future = CompletableFuture + .supplyAsync(() -> processDetokenizeBatch(batch, ctx), executor) + .thenApply(response -> Utils.formatBulkDetokenizeResponse(response.body(), batchNumber, batchSize, response.headers())) + .exceptionally(ex -> { + errorTokens.addAll(Utils.handleBulkDetokenizeBatchException(ex, batch, batchNumber, batchSize)); + return null; + }); + futures.add(future); + } + } catch (Exception e) { + ErrorRecord errorRecord = new ErrorRecord(0, e.getMessage(), 500); + errorTokens.add(errorRecord); + } + return futures; + } + + private ApiClientHttpResponse processDetokenizeBatch( + com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest batch, + RequestContext ctx) { + return this.getRecordsApi().withRawResponse().detokenize(batch, buildRequestOptions(ctx)); + } + + private List> insertBatchFutures( + V1InsertRequest insertRequest, + List errorRecords, + RequestInterceptor interceptor, + BatchConfig cfg) { + List records = insertRequest.getRecords().get(); + + ExecutorService executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); + List> batches = Utils.createBulkInsertBatches(records, cfg.batchSize); + List> futures = new ArrayList<>(); + V1Upsert upsert = insertRequest.getUpsert().isPresent() ? insertRequest.getUpsert().get() : null; + + try { + for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { + List batch = batches.get(batchIndex); + int batchNumber = batchIndex; + RequestContext ctx = new RequestContext("INSERT"); + if (interceptor != null) interceptor.intercept(ctx); + CompletableFuture future = CompletableFuture + .supplyAsync(() -> insertBatch(batch, insertRequest.getTableName().isPresent() ? insertRequest.getTableName().get() : null, upsert, ctx), executor) + .thenApply(response -> Utils.formatBulkInsertResponse(response.body(), batchNumber, cfg.batchSize, response.headers())) + .exceptionally(ex -> { + errorRecords.addAll(Utils.handleBulkInsertBatchException(ex, batch, batchNumber, cfg.batchSize)); + return null; + }); + futures.add(future); + } + } finally { + executor.shutdown(); + } + return futures; + } + + private ApiClientHttpResponse insertBatch(List batch, String tableName, V1Upsert upsert, RequestContext ctx) { + V1InsertRequest.Builder req = V1InsertRequest.builder() + .vaultId(this.getVaultConfig().getVaultId()) + .records(batch) + .upsert(upsert); + if (tableName != null && !tableName.isEmpty()) { + req.tableName(tableName); + } + V1InsertRequest request = req.build(); + return this.getRecordsApi().withRawResponse().insert(request, buildRequestOptions(ctx)); + } + + private BatchConfig configureInsertConcurrencyAndBatchSize(int totalRequests) { + int batchSize = Constants.INSERT_BATCH_SIZE; + int concurrencyLimit; + try { + String userProvidedBatchSize = System.getenv("INSERT_BATCH_SIZE"); + String userProvidedConcurrencyLimit = System.getenv("INSERT_CONCURRENCY_LIMIT"); + + Dotenv dotenv = null; + try { + dotenv = Dotenv.load(); + } catch (DotenvException ignored) { + // ignore the case if .env file is not found + } + + if (userProvidedBatchSize == null && dotenv != null) { + userProvidedBatchSize = dotenv.get("INSERT_BATCH_SIZE"); + } + if (userProvidedConcurrencyLimit == null && dotenv != null) { + userProvidedConcurrencyLimit = dotenv.get("INSERT_CONCURRENCY_LIMIT"); + } + + if (userProvidedBatchSize != null) { + try { + int parsedBatchSize = Integer.parseInt(userProvidedBatchSize); + if (parsedBatchSize > Constants.MAX_INSERT_BATCH_SIZE) { + LogUtil.printWarningLog(WarningLogs.BATCH_SIZE_EXCEEDS_MAX_LIMIT.getLog()); + } + int maxBatchSize = Math.min(parsedBatchSize, Constants.MAX_INSERT_BATCH_SIZE); + if (maxBatchSize > 0) { + batchSize = maxBatchSize; + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.INSERT_BATCH_SIZE; + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_BATCH_SIZE_PROVIDED.getLog()); + batchSize = Constants.INSERT_BATCH_SIZE; + } + } + + // Max no of threads required to run all batches concurrently at once + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + + if (userProvidedConcurrencyLimit != null) { + try { + int parsedConcurrencyLimit = Integer.parseInt(userProvidedConcurrencyLimit); + int maxConcurrencyLimit = Math.min(parsedConcurrencyLimit, Constants.MAX_INSERT_CONCURRENCY_LIMIT); + if (parsedConcurrencyLimit > Constants.MAX_INSERT_CONCURRENCY_LIMIT) { + LogUtil.printWarningLog(WarningLogs.CONCURRENCY_EXCEEDS_MAX_LIMIT.getLog()); + } + if (maxConcurrencyLimit > 0) { + concurrencyLimit = Math.min(maxConcurrencyLimit, maxConcurrencyNeeded); + } else { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.INSERT_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (NumberFormatException e) { + LogUtil.printWarningLog(WarningLogs.INVALID_CONCURRENCY_LIMIT_PROVIDED.getLog()); + concurrencyLimit = Math.min(Constants.INSERT_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } else { + concurrencyLimit = Math.min(Constants.INSERT_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + } catch (Exception e) { + batchSize = Constants.INSERT_BATCH_SIZE; + int maxConcurrencyNeeded = (totalRequests + batchSize - 1) / batchSize; + concurrencyLimit = Math.min(Constants.INSERT_CONCURRENCY_LIMIT, maxConcurrencyNeeded); + } + return new BatchConfig(batchSize, concurrencyLimit); + } -} \ No newline at end of file +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensRequest.java new file mode 100644 index 00000000..8b8e56ea --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensRequest.java @@ -0,0 +1,34 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class BulkDeleteTokensRequest { + private final BulkDeleteTokensRequestBuilder builder; + + private BulkDeleteTokensRequest(BulkDeleteTokensRequestBuilder builder) { + this.builder = builder; + } + + public static BulkDeleteTokensRequestBuilder builder() { + return new BulkDeleteTokensRequestBuilder(); + } + + public List getTokens() { + return this.builder.tokens; + } + + public static final class BulkDeleteTokensRequestBuilder { + private List tokens; + + private BulkDeleteTokensRequestBuilder() {} + + public BulkDeleteTokensRequestBuilder tokens(List tokens) { + this.tokens = tokens; + return this; + } + + public BulkDeleteTokensRequest build() { + return new BulkDeleteTokensRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensResponse.java new file mode 100644 index 00000000..47733c5d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkDeleteTokensResponse.java @@ -0,0 +1,50 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +import java.util.List; + +public class BulkDeleteTokensResponse { + @Expose(serialize = true) + private DeleteTokensSummary summary; + + @Expose(serialize = true) + private List success; + + @Expose(serialize = true) + private List errors; + + private List originalPayload; + + public BulkDeleteTokensResponse(List success, List errors) { + this.success = success; + this.errors = errors; + } + + public BulkDeleteTokensResponse(List success, List errors, List originalPayload) { + this.success = success; + this.errors = errors; + this.originalPayload = originalPayload; + this.summary = new DeleteTokensSummary(this.originalPayload.size(), this.success.size(), this.errors.size()); + } + + public DeleteTokensSummary getSummary() { + return summary; + } + + public List getSuccess() { + return success; + } + + public List getErrors() { + return errors; + } + + @Override + public String toString() { + Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeRequest.java new file mode 100644 index 00000000..a7a842b5 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeRequest.java @@ -0,0 +1,41 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class BulkDetokenizeRequest { + private final BulkDetokenizeRequestBuilder builder; + private BulkDetokenizeRequest(BulkDetokenizeRequestBuilder builder){ + this.builder = builder; + } + + public static BulkDetokenizeRequestBuilder builder(){ + return new BulkDetokenizeRequestBuilder(); + } + public List getTokens(){ + return this.builder.tokens; + } + public List getTokenGroupRedactions(){ + return this.builder.tokenGroupRedactions; + } + + public static final class BulkDetokenizeRequestBuilder{ + private List tokens; + + private List tokenGroupRedactions; + + public BulkDetokenizeRequestBuilder tokens(List tokens){ + this.tokens = tokens; + return this; + } + public BulkDetokenizeRequestBuilder tokenGroupRedactions(List tokenGroupRedactions){ + this.tokenGroupRedactions = tokenGroupRedactions; + return this; + } + public BulkDetokenizeRequest build(){ + return new BulkDetokenizeRequest(this); + } + + + } + +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeResponse.java new file mode 100644 index 00000000..a1ad1ee7 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkDetokenizeResponse.java @@ -0,0 +1,63 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class BulkDetokenizeResponse { + @Expose(serialize = true) + private DetokenizeSummary summary; + + @Expose(serialize = true) + private List success; + + @Expose(serialize = true) + private List errors; + + private List originalPayload; + private List tokensToRetry; + + public BulkDetokenizeResponse(List success, List errors) { + this.success = success; + this.errors = errors; + } + + public BulkDetokenizeResponse(List success, List errors, List originalPayload) { + this.success = success; + this.errors = errors; + this.originalPayload = originalPayload; + this.summary = new DetokenizeSummary(this.originalPayload.size(), this.success.size(), this.errors.size()); + } + + public List getTokensToRetry() { + if (tokensToRetry == null) { + tokensToRetry = new ArrayList<>(); + tokensToRetry = errors.stream() + .filter(error -> (error.getCode() >= 500 && error.getCode() <= 599) && error.getCode() != 529) + .map(errorRecord -> originalPayload.get(errorRecord.getIndex())) + .collect(Collectors.toList()); + } + return tokensToRetry; + } + + public List getSuccess() { + return success; + } + public DetokenizeSummary getSummary() { + return this.summary; + } + + public List getErrors() { + return this.errors; + } + @Override + public String toString() { + Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + return gson.toJson(this); + } + +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRecord.java new file mode 100644 index 00000000..3aeae875 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRecord.java @@ -0,0 +1,68 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.UpsertType; + +import java.util.List; +import java.util.Map; + +public class BulkInsertRecord { + private final BulkInsertRecordBuilder builder; + + private BulkInsertRecord(BulkInsertRecordBuilder builder) { + this.builder = builder; + } + + // Getters + public String getTable() { + return this.builder.table; + } + + public Map getData() { + return this.builder.data; + } + + public List getUpsert() { + return this.builder.upsert; + } + + public UpsertType getUpsertType() { + return this.builder.upsertType; + } + + // Builder Class + public static final class BulkInsertRecordBuilder { + private String table; + private Map data; + private List upsert; + private UpsertType upsertType; + + public BulkInsertRecordBuilder table(String table) { + this.table = table; + return this; + } + + public BulkInsertRecordBuilder data(Map data) { + this.data = data; + return this; + } + + public BulkInsertRecordBuilder upsert(List upsert) { + this.upsert = upsert; + return this; + } + + public BulkInsertRecordBuilder upsertType(UpsertType upsertType) { + this.upsertType = upsertType; + return this; + } + + public BulkInsertRecord build() { + return new BulkInsertRecord(this); + } + } + + // Static entry point for builder + public static BulkInsertRecordBuilder builder() { + return new BulkInsertRecordBuilder(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRequest.java new file mode 100644 index 00000000..7eda6f93 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertRequest.java @@ -0,0 +1,69 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.UpsertType; + +import java.util.ArrayList; +import java.util.List; + +public class BulkInsertRequest extends BaseInsertRequest { + private final BulkInsertRequestBuilder builder; + + private BulkInsertRequest(BulkInsertRequestBuilder builder) { + super(builder); + this.builder = builder; + } + + + public static BulkInsertRequestBuilder builder() { + return new BulkInsertRequestBuilder(); + } + + public List getUpsert() { + return this.builder.upsert; + } + + public UpsertType getUpsertType() { + return this.builder.upsertType; + } + + public ArrayList getRecords(){ + return this.builder.records; + } + + public static final class BulkInsertRequestBuilder extends BaseInsertRequestBuilder { + private List upsert; + + private UpsertType upsertType; + + private ArrayList records; + + private BulkInsertRequestBuilder() { + super(); + } + + @Override + public BulkInsertRequestBuilder table(String table) { + super.table(table); + return this; + } + + public BulkInsertRequestBuilder upsert(List upsert) { + this.upsert = upsert; + return this; + } + + public BulkInsertRequestBuilder upsertType(UpsertType upsertType) { + this.upsertType = upsertType; + return this; + } + + public BulkInsertRequestBuilder records(ArrayList records){ + this.records = records; + return this; + } + + public BulkInsertRequest build() { + return new BulkInsertRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertResponse.java new file mode 100644 index 00000000..72f542d0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkInsertResponse.java @@ -0,0 +1,68 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class BulkInsertResponse { + // These members will be included in the toString() output + @Expose(serialize = true) + private Summary summary; + @Expose(serialize = true) + private List success; + @Expose(serialize = true) + private List errors; + + // Internal fields. Should not be included in toString() output + private ArrayList originalPayload; + private ArrayList recordsToRetry; + + public BulkInsertResponse(List successRecords, List errorRecords) { + this.success = successRecords; + this.errors = errorRecords; + } + + public BulkInsertResponse( + List successRecords, + List errorRecords, + ArrayList originalPayload + ) { + this.success = successRecords; + this.errors = errorRecords; + this.originalPayload = originalPayload; + this.summary = new Summary(this.originalPayload.size(), this.success.size(), this.errors.size()); + } + + public Summary getSummary() { + return this.summary; + } + + public List getSuccess() { + return this.success; + } + + public List getErrors() { + return this.errors; + } + + public ArrayList getRecordsToRetry() { + if (recordsToRetry == null) { + recordsToRetry = new ArrayList<>(); + recordsToRetry = errors.stream() + .filter(error -> (error.getCode() >= 500 && error.getCode() <= 599) && error.getCode() != 529) + .map(errorRecord -> originalPayload.get(errorRecord.getIndex())) + .collect(Collectors.toCollection(ArrayList::new)); + } + return recordsToRetry; + } + + @Override + public String toString() { + Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenGroupRedactions.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenGroupRedactions.java new file mode 100644 index 00000000..da894232 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenGroupRedactions.java @@ -0,0 +1,39 @@ +package com.skyflow.vault.data; + +public class BulkTokenGroupRedactions { + private final BulkTokenGroupRedactionsBuilder builder; + + private BulkTokenGroupRedactions(BulkTokenGroupRedactionsBuilder builder) { + this.builder = builder; + } + public String getTokenGroupName() { + return this.builder.tokenGroupName; + } + + public String getRedaction() { + return this.builder.redaction; + } + + public static BulkTokenGroupRedactionsBuilder builder() { + return new BulkTokenGroupRedactionsBuilder(); + } + + public static final class BulkTokenGroupRedactionsBuilder { + private String tokenGroupName; + private String redaction; + + public BulkTokenGroupRedactionsBuilder tokenGroupName(String tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + public BulkTokenGroupRedactionsBuilder redaction(String redaction) { + this.redaction = redaction; + return this; + } + + public BulkTokenGroupRedactions build() { + return new BulkTokenGroupRedactions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRecord.java new file mode 100644 index 00000000..5275e8db --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRecord.java @@ -0,0 +1,44 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class BulkTokenizeRecord { + private final BulkTokenizeRecordBuilder builder; + + private BulkTokenizeRecord(BulkTokenizeRecordBuilder builder) { + this.builder = builder; + } + + public static BulkTokenizeRecordBuilder builder() { + return new BulkTokenizeRecordBuilder(); + } + + public Object getValue() { + return this.builder.value; + } + + public List getTokenGroupNames() { + return this.builder.tokenGroupNames; + } + + public static final class BulkTokenizeRecordBuilder { + private Object value; + private List tokenGroupNames; + + private BulkTokenizeRecordBuilder() {} + + public BulkTokenizeRecordBuilder value(Object value) { + this.value = value; + return this; + } + + public BulkTokenizeRecordBuilder tokenGroupNames(List tokenGroupNames) { + this.tokenGroupNames = tokenGroupNames; + return this; + } + + public BulkTokenizeRecord build() { + return new BulkTokenizeRecord(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRequest.java new file mode 100644 index 00000000..47f2ef36 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeRequest.java @@ -0,0 +1,34 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; + +public class BulkTokenizeRequest { + private final BulkTokenizeRequestBuilder builder; + + private BulkTokenizeRequest(BulkTokenizeRequestBuilder builder) { + this.builder = builder; + } + + public static BulkTokenizeRequestBuilder builder() { + return new BulkTokenizeRequestBuilder(); + } + + public ArrayList getData() { + return this.builder.data; + } + + public static final class BulkTokenizeRequestBuilder { + private ArrayList data; + + private BulkTokenizeRequestBuilder() {} + + public BulkTokenizeRequestBuilder data(ArrayList data) { + this.data = data; + return this; + } + + public BulkTokenizeRequest build() { + return new BulkTokenizeRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeResponse.java new file mode 100644 index 00000000..84026905 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/BulkTokenizeResponse.java @@ -0,0 +1,80 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class BulkTokenizeResponse { + @Expose(serialize = true) + private TokenizeSummary summary; + + @Expose(serialize = true) + private List success; + + @Expose(serialize = true) + private List errors; + + private List originalPayload; + + public BulkTokenizeResponse(List success, List errors) { + this.success = success; + this.errors = errors; + } + + public BulkTokenizeResponse(List success, List errors, List originalPayload) { + this.success = success; + this.errors = errors; + this.originalPayload = originalPayload; + + int totalTokens = originalPayload.size(); + + // Collect indices that appear in success and in errors + Set successIndices = new HashSet<>(); + for (TokenizeSuccess s : this.success) { + successIndices.add(s.getIndex()); + } + Set errorIndices = new HashSet<>(); + for (ErrorRecord e : this.errors) { + errorIndices.add(e.getIndex()); + } + + // totalTokenized = ALL token groups succeeded (in success, NOT in errors) + // totalPartial = SOME succeeded, SOME failed (in both success AND errors) + // totalFailed = ALL token groups failed (in errors, NOT in success) + int totalTokenized = 0; + int totalPartial = 0; + int totalFailed = 0; + for (int i = 0; i < totalTokens; i++) { + boolean hasSuccess = successIndices.contains(i); + boolean hasError = errorIndices.contains(i); + if (hasSuccess && !hasError) totalTokenized++; + else if (hasSuccess && hasError) totalPartial++; + else if (!hasSuccess && hasError) totalFailed++; + // else: index not present in either (shouldn't happen in practice) + } + + this.summary = new TokenizeSummary(totalTokens, totalTokenized, totalPartial, totalFailed); + } + + public TokenizeSummary getSummary() { + return summary; + } + + public List getSuccess() { + return success; + } + + public List getErrors() { + return errors; + } + + @Override + public String toString() { + Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensOptions.java new file mode 100644 index 00000000..622f531e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensOptions.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.data; + +public final class DeleteTokensOptions { + private final RequestInterceptor interceptor; + + private DeleteTokensOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public DeleteTokensOptions build() { + return new DeleteTokensOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSuccess.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSuccess.java new file mode 100644 index 00000000..15da5a46 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSuccess.java @@ -0,0 +1,31 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; + +public class DeleteTokensSuccess { + @Expose(serialize = true) + private int index; + + @Expose(serialize = true) + private String token; + + public DeleteTokensSuccess(int index, String token) { + this.index = index; + this.token = token; + } + + public int getIndex() { + return index; + } + + public String getToken() { + return token; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSummary.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSummary.java new file mode 100644 index 00000000..92770caf --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteTokensSummary.java @@ -0,0 +1,41 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; + +public class DeleteTokensSummary { + @Expose(serialize = true) + private int totalTokens; + + @Expose(serialize = true) + private int totalDeleted; + + @Expose(serialize = true) + private int totalFailed; + + public DeleteTokensSummary() {} + + public DeleteTokensSummary(int totalTokens, int totalDeleted, int totalFailed) { + this.totalTokens = totalTokens; + this.totalDeleted = totalDeleted; + this.totalFailed = totalFailed; + } + + public int getTotalTokens() { + return totalTokens; + } + + public int getTotalDeleted() { + return totalDeleted; + } + + public int getTotalFailed() { + return totalFailed; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeOptions.java new file mode 100644 index 00000000..267bd9bd --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeOptions.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.data; + +public final class DetokenizeOptions { + private final RequestInterceptor interceptor; + + private DetokenizeOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public DetokenizeOptions build() { + return new DetokenizeOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponseObject.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponseObject.java new file mode 100644 index 00000000..0e1c57f6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeResponseObject.java @@ -0,0 +1,63 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; + +import java.util.Map; + +public class DetokenizeResponseObject { + @Expose(serialize = true) + private int index; + + @Expose(serialize = true) + private String token; + @Expose(serialize = true) + private Object value; + @Expose(serialize = true) + private String tokenGroupName; + @Expose(serialize = true) + private String error; + + @Expose(serialize = true) + private Map metadata; + + public DetokenizeResponseObject(int index, String token, Object value, String tokenGroupName, String error, Map metadata) { + this.token = token; + this.value = value; + this.tokenGroupName = tokenGroupName; + this.error = error; + this.metadata = metadata; + this.index = index; + } + + public String getToken() { + return token; + } + + public Object getValue() { + return value; + } + + public String getTokenGroupName() { + return tokenGroupName; + } + + public String getError() { + return error; + } + + public int getIndex() { + return index; + } + + public Map getMetadata() { + return metadata; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeSummary.java b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeSummary.java new file mode 100644 index 00000000..c86c1854 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DetokenizeSummary.java @@ -0,0 +1,40 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; + +public class DetokenizeSummary { + @Expose(serialize = true) + private int totalTokens; + @Expose(serialize = true) + private int totalDetokenized; + @Expose(serialize = true) + private int totalFailed; + + public DetokenizeSummary() { + } + + public DetokenizeSummary(int totalTokens, int totalDetokenized, int totalFailed) { + this.totalTokens = totalTokens; + this.totalDetokenized = totalDetokenized; + this.totalFailed = totalFailed; + } + + public int getTotalTokens() { + return totalTokens; + } + + public int getTotalDetokenized() { + return totalDetokenized; + } + + public int getTotalFailed() { + return totalFailed; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/ErrorRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/ErrorRecord.java new file mode 100644 index 00000000..1536c0f9 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/ErrorRecord.java @@ -0,0 +1,51 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; + +public class ErrorRecord { + @Expose(serialize = true) + private int index; + @Expose(serialize = true) + private String error; + @Expose(serialize = true) + private int code; + @Expose(serialize = true) + private String requestId; + + public ErrorRecord(int index, String error, int code) { + this.index = index; + this.error = error; + this.code = code; + } + + public ErrorRecord(int index, String error, int code, String requestId) { + this.index = index; + this.error = error; + this.code = code; + this.requestId = requestId; + } + + public String getError() { + return error; + } + + public int getCode() { + return code; + } + + public int getIndex() { + return index; + } + + public String getRequestId() { + return requestId; + } + + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/Success.java b/flowvault/src/main/java/com/skyflow/vault/data/Success.java new file mode 100644 index 00000000..59cdf722 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/Success.java @@ -0,0 +1,53 @@ +package com.skyflow.vault.data; +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; + +import java.util.List; +import java.util.Map; + +public class Success { + @Expose(serialize = true) + private int index; + @Expose(serialize = true) + private String skyflow_id; + @Expose(serialize = true) + private Map> tokens; + @Expose(serialize = true) + private Map data; + @Expose(serialize = true) + private String table; + + public int getIndex() { + return index; + } + + public Success(int index, String skyflow_id, Map> tokens, Map data, String table) { + this.index = index; + this.skyflow_id = skyflow_id; + this.tokens = tokens; + this.data = data; + this.table = table; + } + + public String getSkyflowId() { + return this.skyflow_id; + } + + public Map> getTokens() { + return this.tokens; + } + + public Map getData() { + return this.data; + } + + public String getTable(){ + return this.table; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/Summary.java b/flowvault/src/main/java/com/skyflow/vault/data/Summary.java new file mode 100644 index 00000000..fb152fb2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/Summary.java @@ -0,0 +1,42 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; + +public class Summary { + @Expose(serialize = true) + private int totalRecords; + @Expose(serialize = true) + private int totalInserted; + @Expose(serialize = true) + private int totalFailed; + + public Summary() { + } + + public Summary(int totalRecords, int totalInserted, int totalFailed) { + this.totalRecords = totalRecords; + this.totalInserted = totalInserted; + this.totalFailed = totalFailed; + } + + public int getTotalRecords() { + return totalRecords; + } + + + public int getTotalInserted() { + return totalInserted; + } + + public int getTotalFailed() { + return totalFailed; + } + + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/Token.java b/flowvault/src/main/java/com/skyflow/vault/data/Token.java new file mode 100644 index 00000000..c50242bb --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/Token.java @@ -0,0 +1,23 @@ +package com.skyflow.vault.data; + +import com.google.gson.annotations.Expose; + +public class Token { + @Expose(serialize = true) + private String token; + @Expose(serialize = true) + private String tokenGroupName; + + public String getToken() { + return token; + } + + public String getTokenGroupName() { + return tokenGroupName; + } + + public Token(String token, String tokenGroupName) { + this.token = token; + this.tokenGroupName = tokenGroupName; + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeOptions.java new file mode 100644 index 00000000..2ac5bcfd --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeOptions.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.data; + +public final class TokenizeOptions { + private final RequestInterceptor interceptor; + + private TokenizeOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public TokenizeOptions build() { + return new TokenizeOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeSuccess.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeSuccess.java new file mode 100644 index 00000000..59ee4b65 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeSuccess.java @@ -0,0 +1,53 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Represents one successfully tokenized input record. + * All tokens generated for this record (one per tokenGroupName) are grouped + * under the {@code tokens} map: tokenGroupName → token value. + */ +public class TokenizeSuccess { + @Expose(serialize = true) + private int index; + + @Expose(serialize = true) + private Object value; + + @Expose(serialize = true) + private Map tokens; + + public TokenizeSuccess(int index, Object value) { + this.index = index; + this.value = value; + this.tokens = new LinkedHashMap<>(); + } + + /** Adds a token for a specific token group name. */ + public void addToken(String tokenGroupName, String token) { + this.tokens.put(tokenGroupName, token); + } + + public int getIndex() { + return index; + } + + public Object getValue() { + return value; + } + + public Map getTokens() { + return tokens; + } + + @Override + public String toString() { + Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/TokenizeSummary.java b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeSummary.java new file mode 100644 index 00000000..b9a692c0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/TokenizeSummary.java @@ -0,0 +1,39 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +public class TokenizeSummary { + @Expose(serialize = true) + private int totalTokens; + + @Expose(serialize = true) + private int totalTokenized; + + @Expose(serialize = true) + private int totalPartial; + + @Expose(serialize = true) + private int totalFailed; + + public TokenizeSummary() {} + + public TokenizeSummary(int totalTokens, int totalTokenized, int totalPartial, int totalFailed) { + this.totalTokens = totalTokens; + this.totalTokenized = totalTokenized; + this.totalPartial = totalPartial; + this.totalFailed = totalFailed; + } + + public int getTotalTokens() { return totalTokens; } + public int getTotalTokenized() { return totalTokenized; } + public int getTotalPartial() { return totalPartial; } + public int getTotalFailed() { return totalFailed; } + + @Override + public String toString() { + Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + return gson.toJson(this); + } +} diff --git a/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java index 425f461a..d5214913 100644 --- a/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java @@ -6,6 +6,7 @@ import com.skyflow.enums.Env; import com.skyflow.enums.UpsertType; import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest; import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest; @@ -18,14 +19,27 @@ import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; import com.skyflow.generated.rest.types.V1FlowTokenizeResponseObject; +import com.skyflow.generated.rest.types.V1InsertRecordData; import com.skyflow.generated.rest.types.V1InsertResponse; import com.skyflow.generated.rest.types.V1RecordResponseObject; +import com.skyflow.vault.data.BulkDeleteTokensRequest; +import com.skyflow.vault.data.BulkDeleteTokensResponse; +import com.skyflow.vault.data.BulkDetokenizeRequest; +import com.skyflow.vault.data.BulkDetokenizeResponse; +import com.skyflow.vault.data.BulkInsertRecord; +import com.skyflow.vault.data.BulkInsertRequest; +import com.skyflow.vault.data.BulkInsertResponse; +import com.skyflow.vault.data.BulkTokenGroupRedactions; +import com.skyflow.vault.data.BulkTokenizeRecord; +import com.skyflow.vault.data.BulkTokenizeRequest; +import com.skyflow.vault.data.BulkTokenizeResponse; import com.skyflow.vault.data.DeleteTokensRequest; import com.skyflow.vault.data.DeleteTokensResponse; import com.skyflow.vault.data.DetokenizeData; import com.skyflow.vault.data.DetokenizeRecordResponse; import com.skyflow.vault.data.DetokenizeRequest; import com.skyflow.vault.data.DetokenizeResponse; +import com.skyflow.vault.data.ErrorRecord; import com.skyflow.vault.data.InsertRecord; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertResponse; @@ -38,6 +52,7 @@ import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -565,4 +580,571 @@ public void testBuildDeleteTokensResponse_incompleteResponseDoesNotThrow() { Assert.assertEquals(1, response.getTokens().size()); } + + // ── getBulkInsertRequestBody (bulk overload) ────────────────────────────── + + @Test + public void testGetBulkInsertRequestBody_bulk_buildsCorrectRequest() { + Map data = new HashMap<>(); + data.put("name", "john"); + BulkInsertRecord record = BulkInsertRecord.builder().data(data).build(); + ArrayList records = new ArrayList<>(); + records.add(record); + BulkInsertRequest request = BulkInsertRequest.builder().table("table1").records(records).build(); + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + + V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals("table1", body.getTableName().get()); + Assert.assertEquals(1, body.getRecords().get().size()); + Assert.assertEquals(data, body.getRecords().get().get(0).getData().get()); + } + + @Test + public void testGetBulkInsertRequestBody_bulk_withUpsertAtRequestLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + BulkInsertRecord record = BulkInsertRecord.builder().data(data).build(); + ArrayList records = new ArrayList<>(); + records.add(record); + BulkInsertRequest request = BulkInsertRequest.builder() + .table("table1") + .records(records) + .upsert(Collections.singletonList("email")) + .upsertType(UpsertType.UPDATE) + .build(); + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + + V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + + Assert.assertTrue(body.getUpsert().isPresent()); + Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns().get()); + Assert.assertEquals(FlowEnumUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); + } + + @Test + public void testGetBulkInsertRequestBody_bulk_withUpsertAtRecordLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + BulkInsertRecord record = BulkInsertRecord.builder() + .table("table1") + .data(data) + .upsert(Collections.singletonList("email")) + .upsertType(UpsertType.REPLACE) + .build(); + ArrayList records = new ArrayList<>(); + records.add(record); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + + V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + + Assert.assertEquals("table1", body.getRecords().get().get(0).getTableName().get()); + Assert.assertTrue(body.getRecords().get().get(0).getUpsert().isPresent()); + Assert.assertEquals(FlowEnumUpdateType.REPLACE, body.getRecords().get().get(0).getUpsert().get().getUpdateType().get()); + } + + // ── getBulkDetokenizeRequestBody ────────────────────────────────────────── + + @Test + public void testGetBulkDetokenizeRequestBody_buildsCorrectRequest() { + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Arrays.asList("token1", "token2")) + .build(); + + V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals(Arrays.asList("token1", "token2"), body.getTokens().get()); + Assert.assertFalse(body.getTokenGroupRedactions().isPresent()); + } + + @Test + public void testGetBulkDetokenizeRequestBody_withTokenGroupRedactions() { + BulkTokenGroupRedactions redaction = BulkTokenGroupRedactions.builder() + .tokenGroupName("group1") + .redaction("MASKED") + .build(); + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .tokenGroupRedactions(Collections.singletonList(redaction)) + .build(); + + V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, "vault123"); + + Assert.assertTrue(body.getTokenGroupRedactions().isPresent()); + Assert.assertEquals(1, body.getTokenGroupRedactions().get().size()); + Assert.assertEquals("group1", body.getTokenGroupRedactions().get().get(0).getTokenGroupName().get()); + Assert.assertEquals("MASKED", body.getTokenGroupRedactions().get().get(0).getRedaction().get()); + } + + // ── getBulkDeleteTokensRequestBody ───────────────────────────────────────── + + @Test + public void testGetBulkDeleteTokensRequestBody_buildsCorrectRequest() { + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder() + .tokens(Arrays.asList("token1", "token2")) + .build(); + + V1FlowDeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals(Arrays.asList("token1", "token2"), body.getTokens().get()); + } + + // ── getBulkTokenizeRequestBody ───────────────────────────────────────────── + + @Test + public void testGetBulkTokenizeRequestBody_buildsCorrectRequest() { + BulkTokenizeRecord record = BulkTokenizeRecord.builder() + .value("value1") + .tokenGroupNames(Collections.singletonList("group1")) + .build(); + ArrayList data = new ArrayList<>(); + data.add(record); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(data).build(); + + V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals(1, body.getData().get().size()); + Assert.assertEquals("value1", body.getData().get().get(0).getValue().get()); + Assert.assertEquals(Collections.singletonList("group1"), body.getData().get().get(0).getTokenGroupNames().get()); + } + + // ── createBulkInsertBatches ──────────────────────────────────────────────── + + @Test + public void testCreateBulkInsertBatches_splitsEvenly() { + List records = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + records.add(V1InsertRecordData.builder().data(new HashMap<>()).build()); + } + + List> batches = Utils.createBulkInsertBatches(records, 2); + + Assert.assertEquals(2, batches.size()); + Assert.assertEquals(2, batches.get(0).size()); + Assert.assertEquals(2, batches.get(1).size()); + } + + @Test + public void testCreateBulkInsertBatches_splitsWithRemainder() { + List records = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + records.add(V1InsertRecordData.builder().data(new HashMap<>()).build()); + } + + List> batches = Utils.createBulkInsertBatches(records, 2); + + Assert.assertEquals(3, batches.size()); + Assert.assertEquals(1, batches.get(2).size()); + } + + // ── createBulkDetokenizeBatches ──────────────────────────────────────────── + + @Test + public void testCreateBulkDetokenizeBatches_splitsTokens() { + V1FlowDetokenizeRequest request = V1FlowDetokenizeRequest.builder() + .vaultId("vault123") + .tokens(Arrays.asList("t1", "t2", "t3")) + .build(); + + List batches = Utils.createBulkDetokenizeBatches(request, 2); + + Assert.assertEquals(2, batches.size()); + Assert.assertEquals(Arrays.asList("t1", "t2"), batches.get(0).getTokens().get()); + Assert.assertEquals(Collections.singletonList("t3"), batches.get(1).getTokens().get()); + Assert.assertEquals("vault123", batches.get(0).getVaultId().get()); + } + + @Test + public void testCreateBulkDetokenizeBatches_carriesTokenGroupRedactions() { + com.skyflow.generated.rest.types.V1TokenGroupRedactions redaction = + com.skyflow.generated.rest.types.V1TokenGroupRedactions.builder() + .tokenGroupName("group1") + .redaction("MASKED") + .build(); + V1FlowDetokenizeRequest request = V1FlowDetokenizeRequest.builder() + .vaultId("vault123") + .tokens(Arrays.asList("t1", "t2")) + .tokenGroupRedactions(Collections.singletonList(redaction)) + .build(); + + List batches = Utils.createBulkDetokenizeBatches(request, 5); + + Assert.assertEquals(1, batches.size()); + Assert.assertTrue(batches.get(0).getTokenGroupRedactions().isPresent()); + Assert.assertEquals("group1", batches.get(0).getTokenGroupRedactions().get().get(0).getTokenGroupName().get()); + } + + // ── createBulkDeleteTokensBatches ────────────────────────────────────────── + + @Test + public void testCreateBulkDeleteTokensBatches_splitsTokens() { + V1FlowDeleteTokenRequest request = V1FlowDeleteTokenRequest.builder() + .vaultId("vault123") + .tokens(Arrays.asList("t1", "t2", "t3")) + .build(); + + List batches = Utils.createBulkDeleteTokensBatches(request, 2); + + Assert.assertEquals(2, batches.size()); + Assert.assertEquals(Arrays.asList("t1", "t2"), batches.get(0).getTokens().get()); + Assert.assertEquals(Collections.singletonList("t3"), batches.get(1).getTokens().get()); + } + + // ── createBulkTokenizeBatches ────────────────────────────────────────────── + + @Test + public void testCreateBulkTokenizeBatches_splitsData() { + com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject obj1 = + com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject.builder().value("v1").build(); + com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject obj2 = + com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject.builder().value("v2").build(); + V1FlowTokenizeRequest request = V1FlowTokenizeRequest.builder() + .vaultId("vault123") + .data(Arrays.asList(obj1, obj2)) + .build(); + + List batches = Utils.createBulkTokenizeBatches(request, 1); + + Assert.assertEquals(2, batches.size()); + Assert.assertEquals(1, batches.get(0).getData().get().size()); + Assert.assertEquals("v1", batches.get(0).getData().get().get(0).getValue().get()); + Assert.assertEquals("v2", batches.get(1).getData().get().get(0).getValue().get()); + } + + // ── createErrorRecord ────────────────────────────────────────────────────── + + @Test + public void testCreateErrorRecord_withHttpCodeKey() { + Map recordMap = new HashMap<>(); + recordMap.put("http_code", 400); + recordMap.put("error", "bad request"); + + ErrorRecord err = Utils.createErrorRecord(recordMap, 0, "req-1"); + + Assert.assertEquals(400, err.getCode()); + Assert.assertEquals("bad request", err.getError()); + Assert.assertEquals("req-1", err.getRequestId()); + } + + @Test + public void testCreateErrorRecord_withStatusCodeKey() { + Map recordMap = new HashMap<>(); + recordMap.put("statusCode", 500); + recordMap.put("message", "server error"); + + ErrorRecord err = Utils.createErrorRecord(recordMap, 2, null); + + Assert.assertEquals(500, err.getCode()); + Assert.assertEquals("server error", err.getError()); + Assert.assertEquals(2, err.getIndex()); + } + + @Test + public void testCreateErrorRecord_nullMapReturnsNull() { + Assert.assertNull(Utils.createErrorRecord(null, 0, null)); + } + + // ── handleBulkInsertBatchException ──────────────────────────────────────── + + @Test + public void testHandleBulkInsertBatchException_apiExceptionWithRecordsBody() { + Map errorRecordMap = new HashMap<>(); + errorRecordMap.put("error", "duplicate"); + errorRecordMap.put("httpCode", 409); + Map body = new HashMap<>(); + body.put("records", Collections.singletonList(errorRecordMap)); + ApiClientApiException apiEx = new ApiClientApiException("insert failed", 409, body); + RuntimeException wrapper = new RuntimeException(apiEx); + + List batch = Collections.singletonList(V1InsertRecordData.builder().data(new HashMap<>()).build()); + List errors = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(409, errors.get(0).getCode()); + Assert.assertEquals("duplicate", errors.get(0).getError()); + } + + @Test + public void testHandleBulkInsertBatchException_apiExceptionWithNoParsableBody() { + ApiClientApiException apiEx = new ApiClientApiException("insert failed", 401, "unauthorized"); + RuntimeException wrapper = new RuntimeException(apiEx); + + List batch = Arrays.asList( + V1InsertRecordData.builder().data(new HashMap<>()).build(), + V1InsertRecordData.builder().data(new HashMap<>()).build()); + List errors = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); + + Assert.assertEquals(2, errors.size()); + Assert.assertEquals(401, errors.get(0).getCode()); + Assert.assertEquals("insert failed", errors.get(0).getError()); + } + + @Test + public void testHandleBulkInsertBatchException_genericException() { + RuntimeException ex = new RuntimeException("boom"); + List batch = Collections.singletonList(V1InsertRecordData.builder().data(new HashMap<>()).build()); + + List errors = Utils.handleBulkInsertBatchException(ex, batch, 1, 2); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(500, errors.get(0).getCode()); + Assert.assertEquals("boom", errors.get(0).getError()); + Assert.assertEquals(2, errors.get(0).getIndex()); + } + + // ── handleBulkDetokenizeBatchException ──────────────────────────────────── + + @Test + public void testHandleBulkDetokenizeBatchException_genericException() { + RuntimeException ex = new RuntimeException("boom"); + V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + .vaultId("vault123") + .tokens(Collections.singletonList("t1")) + .build(); + + List errors = Utils.handleBulkDetokenizeBatchException(ex, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(500, errors.get(0).getCode()); + } + + // ── handleBulkDeleteTokensBatchException ────────────────────────────────── + + @Test + public void testHandleBulkDeleteTokensBatchException_apiExceptionWithTokensBody() { + Map errorRecordMap = new HashMap<>(); + errorRecordMap.put("error", "not found"); + errorRecordMap.put("httpCode", 404); + Map body = new HashMap<>(); + body.put("tokens", Collections.singletonList(errorRecordMap)); + ApiClientApiException apiEx = new ApiClientApiException("delete failed", 404, body); + RuntimeException wrapper = new RuntimeException(apiEx); + + V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + .vaultId("vault123") + .tokens(Collections.singletonList("t1")) + .build(); + List errors = Utils.handleBulkDeleteTokensBatchException(wrapper, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(404, errors.get(0).getCode()); + Assert.assertEquals("not found", errors.get(0).getError()); + } + + @Test + public void testHandleBulkDeleteTokensBatchException_genericException() { + RuntimeException ex = new RuntimeException("boom"); + V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + .vaultId("vault123") + .tokens(Collections.singletonList("t1")) + .build(); + + List errors = Utils.handleBulkDeleteTokensBatchException(ex, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(500, errors.get(0).getCode()); + } + + // ── handleBulkTokenizeBatchException ─────────────────────────────────────── + + @Test + public void testHandleBulkTokenizeBatchException_genericException() { + RuntimeException ex = new RuntimeException("boom"); + V1FlowTokenizeRequest batch = V1FlowTokenizeRequest.builder() + .vaultId("vault123") + .data(Collections.singletonList(com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject.builder().value("v1").build())) + .build(); + + List errors = Utils.handleBulkTokenizeBatchException(ex, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(500, errors.get(0).getCode()); + } + + // ── formatBulkInsertResponse ─────────────────────────────────────────────── + + @Test + public void testFormatBulkInsertResponse_success() { + Map tokens = new HashMap<>(); + tokens.put("name", "tok-abc"); + V1RecordResponseObject record = V1RecordResponseObject.builder() + .skyflowId("sky-id-1") + .tokens(tokens) + .build(); + V1InsertResponse response = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + + BulkInsertResponse result = Utils.formatBulkInsertResponse(response, 0, 50, new HashMap<>()); + + Assert.assertEquals(1, result.getSuccess().size()); + Assert.assertEquals("sky-id-1", result.getSuccess().get(0).getSkyflowId()); + Assert.assertTrue(result.getErrors().isEmpty()); + } + + @Test + public void testFormatBulkInsertResponse_errorWithMissingHttpCodeDefaultsTo500() { + V1RecordResponseObject record = V1RecordResponseObject.builder() + .error("insert failed") + .build(); + V1InsertResponse response = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + + BulkInsertResponse result = Utils.formatBulkInsertResponse(response, 0, 50, new HashMap<>()); + + Assert.assertEquals(1, result.getErrors().size()); + Assert.assertEquals(500, result.getErrors().get(0).getCode()); + Assert.assertEquals("insert failed", result.getErrors().get(0).getError()); + } + + @Test + public void testFormatBulkInsertResponse_nullResponseReturnsNull() { + Assert.assertNull(Utils.formatBulkInsertResponse(null, 0, 50, new HashMap<>())); + } + + // ── formatBulkDetokenizeResponse ─────────────────────────────────────────── + + @Test + public void testFormatBulkDetokenizeResponse_success() { + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1") + .value("secret-value") + .build(); + V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)) + .build(); + + BulkDetokenizeResponse result = Utils.formatBulkDetokenizeResponse(response, 0, 50, new HashMap<>()); + + Assert.assertEquals(1, result.getSuccess().size()); + Assert.assertEquals("secret-value", result.getSuccess().get(0).getValue()); + Assert.assertTrue(result.getErrors().isEmpty()); + } + + @Test + public void testFormatBulkDetokenizeResponse_errorWithMissingHttpCodeDefaultsTo500() { + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1") + .error("token not found") + .build(); + V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)) + .build(); + + BulkDetokenizeResponse result = Utils.formatBulkDetokenizeResponse(response, 0, 50, new HashMap<>()); + + Assert.assertEquals(1, result.getErrors().size()); + Assert.assertEquals(500, result.getErrors().get(0).getCode()); + } + + @Test + public void testFormatBulkDetokenizeResponse_emptyResponseReturnsNull() { + V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder().build(); + Assert.assertNull(Utils.formatBulkDetokenizeResponse(response, 0, 50, new HashMap<>())); + } + + // ── formatBulkDeleteTokensResponse ───────────────────────────────────────── + + @Test + public void testFormatBulkDeleteTokensResponse_success() { + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + .value("token1") + .build(); + V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)) + .build(); + + BulkDeleteTokensResponse result = Utils.formatBulkDeleteTokensResponse(response, 0, 50, new HashMap<>()); + + Assert.assertEquals(1, result.getSuccess().size()); + Assert.assertEquals("token1", result.getSuccess().get(0).getToken()); + Assert.assertTrue(result.getErrors().isEmpty()); + } + + @Test + public void testFormatBulkDeleteTokensResponse_error() { + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + .error("token not found") + .httpCode(404) + .build(); + V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)) + .build(); + + BulkDeleteTokensResponse result = Utils.formatBulkDeleteTokensResponse(response, 0, 50, new HashMap<>()); + + Assert.assertEquals(1, result.getErrors().size()); + Assert.assertEquals(404, result.getErrors().get(0).getCode()); + } + + @Test + public void testFormatBulkDeleteTokensResponse_emptyResponseReturnsNull() { + V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder().build(); + Assert.assertNull(Utils.formatBulkDeleteTokensResponse(response, 0, 50, new HashMap<>())); + } + + // ── formatBulkTokenizeResponse ───────────────────────────────────────────── + + @Test + public void testFormatBulkTokenizeResponse_success() { + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1") + .token("tok-abc") + .build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1") + .tokens(Collections.singletonList(token)) + .build(); + V1FlowTokenizeResponse response = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)) + .build(); + V1FlowTokenizeRequest batchRequest = V1FlowTokenizeRequest.builder() + .vaultId("vault123") + .data(Collections.singletonList(com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject.builder().value("value1").build())) + .build(); + + BulkTokenizeResponse result = Utils.formatBulkTokenizeResponse(response, batchRequest, 0, 50, new HashMap<>()); + + Assert.assertEquals(1, result.getSuccess().size()); + Assert.assertEquals("tok-abc", result.getSuccess().get(0).getTokens().get("group1")); + Assert.assertTrue(result.getErrors().isEmpty()); + } + + @Test + public void testFormatBulkTokenizeResponse_tokenError() { + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1") + .error("invalid value") + .httpCode(400) + .build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1") + .tokens(Collections.singletonList(token)) + .build(); + V1FlowTokenizeResponse response = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)) + .build(); + V1FlowTokenizeRequest batchRequest = V1FlowTokenizeRequest.builder() + .vaultId("vault123") + .data(Collections.singletonList(com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject.builder().value("value1").build())) + .build(); + + BulkTokenizeResponse result = Utils.formatBulkTokenizeResponse(response, batchRequest, 0, 50, new HashMap<>()); + + Assert.assertTrue(result.getSuccess().isEmpty()); + Assert.assertEquals(1, result.getErrors().size()); + Assert.assertEquals(400, result.getErrors().get(0).getCode()); + } + + @Test + public void testFormatBulkTokenizeResponse_emptyResponseReturnsNull() { + V1FlowTokenizeResponse response = V1FlowTokenizeResponse.builder().build(); + V1FlowTokenizeRequest batchRequest = V1FlowTokenizeRequest.builder().vaultId("vault123").build(); + Assert.assertNull(Utils.formatBulkTokenizeResponse(response, batchRequest, 0, 50, new HashMap<>())); + } } diff --git a/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java index 2167fd30..72ae2293 100644 --- a/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java @@ -4,6 +4,13 @@ import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.data.BulkDeleteTokensRequest; +import com.skyflow.vault.data.BulkInsertRecord; +import com.skyflow.vault.data.BulkInsertRequest; +import com.skyflow.vault.data.BulkDetokenizeRequest; +import com.skyflow.vault.data.BulkTokenGroupRedactions; +import com.skyflow.vault.data.BulkTokenizeRecord; +import com.skyflow.vault.data.BulkTokenizeRequest; import com.skyflow.vault.data.DeleteTokensRequest; import com.skyflow.vault.data.DetokenizeData; import com.skyflow.vault.data.DetokenizeRequest; @@ -729,4 +736,389 @@ public void testValidateDetokenizeRequest_validRequestWithTokenGroupRedactions() Assert.fail(INVALID_EXCEPTION_THROWN); } } + + // ── validateBulkInsertRequest ────────────────────────────────────────────── + + @Test + public void testValidateBulkInsertRequest_nullRecords() { + BulkInsertRequest request = BulkInsertRequest.builder().records(null).build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_emptyRecords() { + BulkInsertRequest request = BulkInsertRequest.builder().records(new ArrayList<>()).build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_nullRecordInList() { + ArrayList records = new ArrayList<>(); + records.add(null); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_tableSpecifiedAtBothPlaces() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().table("table1").records(records).build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_tableNotSpecifiedAnywhere() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_emptyKeyInData() { + Map data = new HashMap<>(); + data.put("", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_emptyValueInData() { + Map data = new HashMap<>(); + data.put("name", ""); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_validRequest() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + try { + Validations.validateBulkInsertRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateBulkInsertRequest_validRequestOver10000Records() { + // Bulk operations rely on batching, not a hard cap — must not throw for large lists. + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + for (int i = 0; i < 10001; i++) { + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + } + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + try { + Validations.validateBulkInsertRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateBulkDetokenizeRequest ────────────────────────────────────────── + + @Test + public void testValidateBulkDetokenizeRequest_nullRequest() { + try { + Validations.validateBulkDetokenizeRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_nullTokens() { + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder().tokens(null).build(); + try { + Validations.validateBulkDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_emptyTokens() { + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder().tokens(new ArrayList<>()).build(); + try { + Validations.validateBulkDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_nullTokenInList() { + List tokens = new ArrayList<>(); + tokens.add(null); + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder().tokens(tokens).build(); + try { + Validations.validateBulkDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_nullRedactionGroupObject() { + List groupRedactions = new ArrayList<>(); + groupRedactions.add(null); + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateBulkDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_nullGroupNameInRedaction() { + List groupRedactions = Collections.singletonList( + BulkTokenGroupRedactions.builder().redaction("MASKED").build()); + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateBulkDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_nullRedactionInGroup() { + List groupRedactions = Collections.singletonList( + BulkTokenGroupRedactions.builder().tokenGroupName("group1").build()); + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateBulkDetokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_validRequest() { + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + try { + Validations.validateBulkDetokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateBulkDetokenizeRequest_validRequestWithRedactions() { + List groupRedactions = Collections.singletonList( + BulkTokenGroupRedactions.builder().tokenGroupName("group1").redaction("MASKED").build()); + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .tokenGroupRedactions(groupRedactions) + .build(); + try { + Validations.validateBulkDetokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateBulkDeleteTokensRequest ──────────────────────────────────────── + + @Test + public void testValidateBulkDeleteTokensRequest_nullRequest() { + try { + Validations.validateBulkDeleteTokensRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDeleteTokensRequest_emptyTokens() { + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder().tokens(new ArrayList<>()).build(); + try { + Validations.validateBulkDeleteTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDeleteTokensRequest_emptyTokenInList() { + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder() + .tokens(Arrays.asList("token1", " ")) + .build(); + try { + Validations.validateBulkDeleteTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkDeleteTokensRequest_validRequest() { + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + try { + Validations.validateBulkDeleteTokensRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateBulkTokenizeRequest ──────────────────────────────────────────── + + @Test + public void testValidateBulkTokenizeRequest_nullRequest() { + try { + Validations.validateBulkTokenizeRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkTokenizeRequest_emptyData() { + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(new ArrayList<>()).build(); + try { + Validations.validateBulkTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkTokenizeRequest_nullRecordInList() { + ArrayList data = new ArrayList<>(); + data.add(null); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(data).build(); + try { + Validations.validateBulkTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkTokenizeRequest_emptyValue() { + ArrayList data = new ArrayList<>(); + data.add(BulkTokenizeRecord.builder().value(" ").build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(data).build(); + try { + Validations.validateBulkTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkTokenizeRequest_emptyGroupNameInList() { + ArrayList data = new ArrayList<>(); + data.add(BulkTokenizeRecord.builder().value("value1").tokenGroupNames(Arrays.asList("group1", " ")).build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(data).build(); + try { + Validations.validateBulkTokenizeRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkTokenizeRequest_validRequestWithTokenGroupNames() { + ArrayList data = new ArrayList<>(); + data.add(BulkTokenizeRecord.builder().value("value1").tokenGroupNames(Collections.singletonList("group1")).build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(data).build(); + try { + Validations.validateBulkTokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateBulkTokenizeRequest_validRequestWithoutTokenGroupNames() { + // Unlike the non-bulk tokenize validator, tokenGroupNames is optional for bulk requests. + ArrayList data = new ArrayList<>(); + data.add(BulkTokenizeRecord.builder().value("value1").build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(data).build(); + try { + Validations.validateBulkTokenizeRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } } diff --git a/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java index 78d6aadd..e0af4549 100644 --- a/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java @@ -3,12 +3,14 @@ import com.skyflow.VaultClient; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; +import com.skyflow.enums.CustomHeaderKey; import com.skyflow.enums.Env; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.ApiClient; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.core.ApiClientException; import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; import com.skyflow.generated.rest.resources.flowservice.RawFlowserviceClient; import com.skyflow.generated.rest.types.FlowTokenizeResponseObjectToken; @@ -21,14 +23,26 @@ import com.skyflow.generated.rest.types.V1InsertResponse; import com.skyflow.generated.rest.types.V1RecordResponseObject; import com.skyflow.utils.Constants; +import com.skyflow.vault.data.BulkDeleteTokensRequest; +import com.skyflow.vault.data.BulkDeleteTokensResponse; +import com.skyflow.vault.data.BulkDetokenizeRequest; +import com.skyflow.vault.data.BulkDetokenizeResponse; +import com.skyflow.vault.data.BulkInsertRecord; +import com.skyflow.vault.data.BulkInsertRequest; +import com.skyflow.vault.data.BulkInsertResponse; +import com.skyflow.vault.data.BulkTokenizeRecord; +import com.skyflow.vault.data.BulkTokenizeRequest; +import com.skyflow.vault.data.BulkTokenizeResponse; import com.skyflow.vault.data.DeleteTokensRequest; import com.skyflow.vault.data.DeleteTokensResponse; import com.skyflow.vault.data.DetokenizeData; import com.skyflow.vault.data.DetokenizeRequest; import com.skyflow.vault.data.DetokenizeResponse; +import com.skyflow.vault.data.InsertOptions; import com.skyflow.vault.data.InsertRecord; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertResponse; +import com.skyflow.vault.data.RequestInterceptor; import com.skyflow.vault.data.TokenizeRecord; import com.skyflow.vault.data.TokenizeRequest; import com.skyflow.vault.data.TokenizeResponse; @@ -37,6 +51,7 @@ import okhttp3.Response; import org.junit.Assert; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.lang.reflect.Field; @@ -44,6 +59,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -442,4 +458,368 @@ public void testDeleteTokens_nullRequestThrowsSkyflowException() throws Exceptio Assert.assertNotNull(e.getMessage()); } } + + // ── insert/detokenize interceptor header wiring ────────────────────────── + + @Test + public void testInsert_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokens = new HashMap<>(); + tokens.put("name", "tok-abc"); + V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); + V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.insert(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder().records(records).build(); + + RequestInterceptor interceptor = ctx -> ctx.addHeader(CustomHeaderKey.SkyflowAccountName, "acct-name"); + InsertOptions options = InsertOptions.builder().interceptor(interceptor).build(); + + controller.insert(request, options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw).insert(any(), captor.capture()); + Assert.assertEquals("acct-name", captor.getValue().getHeaders().get(CustomHeaderKey.SkyflowAccountName.toString())); + } + + @Test + public void testDetokenize_noOptionsDoesNotAddCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1").value("secret-value").build(); + V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + + controller.detokenize(request, null); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw).detokenize(any(), captor.capture()); + Assert.assertNull(captor.getValue().getHeaders().get(CustomHeaderKey.SkyflowAccountID.toString())); + } + + // ── bulkInsert ──────────────────────────────────────────────────────────── + + @Test + public void testBulkInsert_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokens = new HashMap<>(); + tokens.put("name", "tok-abc"); + V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); + V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.insert(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + + BulkInsertResponse response = controller.bulkInsert(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + Assert.assertEquals("sky-id-1", response.getSuccess().get(0).getSkyflowId()); + Assert.assertTrue(response.getErrors().isEmpty()); + Assert.assertEquals(1, response.getSummary().getTotalRecords()); + Assert.assertEquals(1, response.getSummary().getTotalInserted()); + } + + @Test + public void testBulkInsert_invalidRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + BulkInsertRequest request = BulkInsertRequest.builder().records(new ArrayList<>()).build(); + try { + controller.bulkInsert(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testBulkInsertAsync_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokens = new HashMap<>(); + tokens.put("name", "tok-abc"); + V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); + V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.insert(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + + BulkInsertResponse response = controller.bulkInsertAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + Assert.assertEquals("sky-id-1", response.getSuccess().get(0).getSkyflowId()); + } + + @Test + public void testBulkInsert_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokens = new HashMap<>(); + tokens.put("name", "tok-abc"); + V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); + V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.insert(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + + RequestInterceptor interceptor = ctx -> ctx.addHeader(CustomHeaderKey.SkyflowAccountID, "acct-123"); + InsertOptions options = InsertOptions.builder().interceptor(interceptor).build(); + + controller.bulkInsert(request, options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw).insert(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SkyflowAccountID.toString())); + } + + // ── bulkDetokenize ──────────────────────────────────────────────────────── + + @Test + public void testBulkDetokenize_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1").value("secret-value").build(); + V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + BulkDetokenizeResponse response = controller.bulkDetokenize(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + Assert.assertEquals("secret-value", response.getSuccess().get(0).getValue()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBulkDetokenize_nullRequestThrowsSkyflowExceptionNotNPE() throws Exception { + // Regression test: configureDetokenizeConcurrencyAndBatchSize() must run AFTER validation, + // otherwise detokenizeRequest.getTokens().size() NPEs on a null request before validation + // has a chance to reject it gracefully. + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.bulkDetokenize(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } catch (NullPointerException e) { + Assert.fail("Expected SkyflowException, got NullPointerException"); + } + } + + @Test + public void testBulkDetokenizeAsync_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1").value("secret-value").build(); + V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + BulkDetokenizeResponse response = controller.bulkDetokenizeAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + } + + @Test + public void testBulkDetokenizeAsync_nullRequestThrowsSkyflowExceptionNotNPE() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.bulkDetokenizeAsync(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } catch (NullPointerException e) { + Assert.fail("Expected SkyflowException, got NullPointerException"); + } + } + + // ── bulkDeleteTokens ────────────────────────────────────────────────────── + + @Test + public void testBulkDeleteTokens_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder().value("token1").build(); + V1FlowDeleteTokenResponse body = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.deletetoken(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + BulkDeleteTokensResponse response = controller.bulkDeleteTokens(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + Assert.assertEquals("token1", response.getSuccess().get(0).getToken()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBulkDeleteTokens_nullRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.bulkDeleteTokens(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testBulkDeleteTokensAsync_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder().value("token1").build(); + V1FlowDeleteTokenResponse body = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.deletetoken(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + BulkDeleteTokensResponse response = controller.bulkDeleteTokensAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + } + + // ── bulkTokenize ────────────────────────────────────────────────────────── + + @Test + public void testBulkTokenize_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1").token("tok-abc").build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1").tokens(Collections.singletonList(token)).build(); + V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(BulkTokenizeRecord.builder().value("value1").tokenGroupNames(Collections.singletonList("group1")).build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(records).build(); + + BulkTokenizeResponse response = controller.bulkTokenize(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + Assert.assertEquals("tok-abc", response.getSuccess().get(0).getTokens().get("group1")); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testBulkTokenize_nullRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.bulkTokenize(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testBulkTokenizeAsync_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1").token("tok-abc").build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1").tokens(Collections.singletonList(token)).build(); + V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(BulkTokenizeRecord.builder().value("value1").tokenGroupNames(Collections.singletonList("group1")).build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(records).build(); + + BulkTokenizeResponse response = controller.bulkTokenizeAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + } } From a9c2b559e2501169acd094030526e751d990e943 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Mon, 20 Jul 2026 08:57:29 +0530 Subject: [PATCH 22/28] SK-2967 implement client --- .../main/java/com/skyflow/BaseSkyflow.java | 39 ++++++++++--------- .../java/com/skyflow/BaseVaultClient.java | 3 +- .../src/main/java/com/skyflow/ISkyflow.java | 6 +-- .../src/main/java/com/skyflow/Skyflow.java | 22 ++++++++++- v2/src/main/java/com/skyflow/Skyflow.java | 14 ++++++- 5 files changed, 58 insertions(+), 26 deletions(-) diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java index 7e7554ff..f752fdfd 100644 --- a/common/src/main/java/com/skyflow/BaseSkyflow.java +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -16,16 +16,17 @@ import java.util.Map; -abstract class BaseSkyflow implements ISkyflow { - protected final BaseSkyflowClientBuilder builder; +abstract class BaseSkyflow implements ISkyflow { + protected final BaseSkyflowClientBuilder builder; - protected BaseSkyflow(BaseSkyflowClientBuilder builder) { + protected BaseSkyflow(BaseSkyflowClientBuilder builder) { this.builder = builder; LogUtil.printInfoLog(InfoLogs.CLIENT_INITIALIZED.getLog()); } protected abstract Self self(); + @Override public Self addVaultConfig(V vaultConfig) throws SkyflowException { this.builder.addVaultConfigTemplate(vaultConfig); return self(); @@ -35,34 +36,35 @@ public V getVaultConfig(String vaultId) { return this.builder.vaultConfigMap.get(vaultId); } + @Override public Self updateVaultConfig(V vaultConfig) throws SkyflowException { this.builder.updateVaultConfigTemplate(vaultConfig); return self(); } + @Override public Self removeVaultConfig(String vaultId) throws SkyflowException { this.builder.removeVaultConfigTemplate(vaultId); return self(); } + @Override public Self updateSkyflowCredentials(Credentials credentials) throws SkyflowException { this.builder.addSkyflowCredentialsTemplate(credentials); return self(); } + @Override public Self setLogLevel(LogLevel logLevel) { this.builder.setLogLevel(logLevel); return self(); } + @Override public LogLevel getLogLevel() { return this.builder.logLevel; } - public VC vault() throws SkyflowException { - return resolveOrThrow(this.builder.vaultClientsMap, null, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); - } - protected static T resolveOrThrow(Map map, String key, ErrorLogs errorLog, ErrorMessage errorMessage) throws SkyflowException { T value = key != null ? map.get(key) : map.values().stream().findFirst().orElse(null); @@ -73,36 +75,35 @@ protected static T resolveOrThrow(Map map, String key, return value; } - abstract static class BaseSkyflowClientBuilder { + abstract static class BaseSkyflowClientBuilder { protected final LinkedHashMap vaultConfigMap = new LinkedHashMap<>(); - protected final LinkedHashMap vaultClientsMap = new LinkedHashMap<>(); protected Credentials skyflowCredentials; protected LogLevel logLevel = LogLevel.ERROR; protected BaseSkyflowClientBuilder() { } - public BaseSkyflowClientBuilder addVaultConfig(V vaultConfig) throws SkyflowException { + public BaseSkyflowClientBuilder addVaultConfig(V vaultConfig) throws SkyflowException { addVaultConfigTemplate(vaultConfig); return this; } - public BaseSkyflowClientBuilder updateVaultConfig(V vaultConfig) throws SkyflowException { + public BaseSkyflowClientBuilder updateVaultConfig(V vaultConfig) throws SkyflowException { updateVaultConfigTemplate(vaultConfig); return this; } - public BaseSkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { + public BaseSkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException { removeVaultConfigTemplate(vaultId); return this; } - public BaseSkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { + public BaseSkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException { addSkyflowCredentialsTemplate(credentials); return this; } - protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { + protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) { this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel; LogUtil.setupLogger(this.logLevel); LogUtil.printInfoLog(BaseUtils.parameterizedString( @@ -116,7 +117,7 @@ protected final void addVaultConfigTemplate(V vaultConfig) throws SkyflowExcepti validateVaultConfig(vaultConfig); V vaultConfigCopy = cloneVaultConfig(vaultConfig); String vaultId = extractVaultId(vaultConfigCopy); - if (this.vaultClientsMap.containsKey(vaultId)) { + if (this.vaultConfigMap.containsKey(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString( ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultId )); @@ -131,7 +132,7 @@ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowExce LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); validateVaultConfig(vaultConfig); String vaultId = extractVaultId(vaultConfig); - if (!this.vaultClientsMap.containsKey(vaultId)) { + if (!this.vaultConfigMap.containsKey(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString( ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId )); @@ -143,11 +144,11 @@ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowExce } protected final void removeVaultConfigTemplate(String vaultId) throws SkyflowException { - if (!this.vaultClientsMap.containsKey(vaultId)) { + if (!this.vaultConfigMap.containsKey(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId)); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); } - this.vaultClientsMap.remove(vaultId); + onVaultConfigRemoved(vaultId); this.vaultConfigMap.remove(vaultId); } @@ -199,6 +200,8 @@ protected final V mergeVaultConfig(V incoming, V existing) { protected abstract void onVaultConfigUpdated(V updatedConfig) throws SkyflowException; + protected abstract void onVaultConfigRemoved(String vaultId) throws SkyflowException; + protected abstract void onCredentialsUpdated(Credentials credentials) throws SkyflowException; } diff --git a/common/src/main/java/com/skyflow/BaseVaultClient.java b/common/src/main/java/com/skyflow/BaseVaultClient.java index 7ca74cf4..fa648611 100644 --- a/common/src/main/java/com/skyflow/BaseVaultClient.java +++ b/common/src/main/java/com/skyflow/BaseVaultClient.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.skyflow.config.BaseCredentials; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; @@ -24,7 +25,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -class BaseVaultClient { +class BaseVaultClient { protected V vaultConfig; protected OkHttpClient sharedHttpClient; protected String currentVaultURL; diff --git a/common/src/main/java/com/skyflow/ISkyflow.java b/common/src/main/java/com/skyflow/ISkyflow.java index 55879a6c..ac5fd747 100644 --- a/common/src/main/java/com/skyflow/ISkyflow.java +++ b/common/src/main/java/com/skyflow/ISkyflow.java @@ -1,9 +1,11 @@ package com.skyflow; +import com.skyflow.config.BaseCredentials; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.enums.LogLevel; import com.skyflow.errors.SkyflowException; -public interface ISkyflow { +public interface ISkyflow { Self addVaultConfig(V vaultConfig) throws SkyflowException; Self updateVaultConfig(V vaultConfig) throws SkyflowException; @@ -15,6 +17,4 @@ public interface ISkyflow { Self setLogLevel(LogLevel logLevel); LogLevel getLogLevel(); - - VC vault() throws SkyflowException; } diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java index bd3c451f..61a95f9a 100644 --- a/flowvault/src/main/java/com/skyflow/Skyflow.java +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -3,7 +3,9 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.LogLevel; +import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.utils.Constants; import com.skyflow.utils.SdkVersion; @@ -12,10 +14,15 @@ import com.skyflow.utils.validations.Validations; import com.skyflow.vault.controller.VaultController; -public final class Skyflow extends BaseSkyflow { +import java.util.LinkedHashMap; + +public final class Skyflow extends BaseSkyflow { + + private final SkyflowClientBuilder builder; private Skyflow(SkyflowClientBuilder builder) { super(builder); + this.builder = builder; } @Override @@ -33,7 +40,13 @@ public VaultConfig getVaultConfig() { return (VaultConfig) array[0]; } - public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + public VaultController vault() throws SkyflowException { + return resolveOrThrow(this.builder.vaultClientsMap, null, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); + } + + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + private final LinkedHashMap vaultClientsMap = new LinkedHashMap<>(); + @Override protected void validateVaultConfig(VaultConfig vaultConfig) throws SkyflowException { Validations.validateVaultConfiguration(vaultConfig); @@ -50,6 +63,11 @@ protected void onVaultConfigUpdated(VaultConfig updatedConfig) throws SkyflowExc this.vaultClientsMap.put(updatedConfig.getVaultId(), new VaultController(updatedConfig, this.skyflowCredentials)); } + @Override + protected void onVaultConfigRemoved(String vaultId) throws SkyflowException { + this.vaultClientsMap.remove(vaultId); + } + @Override protected void onCredentialsUpdated(Credentials credentials) throws SkyflowException { for (VaultController vault : this.vaultClientsMap.values()) { diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index b8a056de..16614481 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -18,7 +18,7 @@ import java.util.LinkedHashMap; -public final class Skyflow extends BaseSkyflow { +public final class Skyflow extends BaseSkyflow { private final SkyflowClientBuilder builder; private Skyflow(SkyflowClientBuilder builder) { @@ -61,6 +61,10 @@ public Skyflow updateLogLevel(LogLevel logLevel) { return setLogLevel(logLevel); } + public VaultController vault() throws SkyflowException { + return resolveOrThrow(this.builder.vaultClientsMap, null, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); + } + public VaultController vault(String vaultId) throws SkyflowException { return resolveOrThrow(this.builder.vaultClientsMap, vaultId, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } @@ -81,7 +85,8 @@ public DetectController detect(String vaultId) throws SkyflowException { return resolveOrThrow(this.builder.detectClientsMap, vaultId, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } - public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder { + private final LinkedHashMap vaultClientsMap = new LinkedHashMap<>(); private final LinkedHashMap connectionsMap = new LinkedHashMap<>(); private final LinkedHashMap detectClientsMap = new LinkedHashMap<>(); private final LinkedHashMap connectionConfigMap = new LinkedHashMap<>(); @@ -104,6 +109,11 @@ protected void onVaultConfigUpdated(VaultConfig updatedConfig) throws SkyflowExc this.vaultClientsMap.get(updatedConfig.getVaultId()).updateVaultConfig(); } + @Override + protected void onVaultConfigRemoved(String vaultId) throws SkyflowException { + this.vaultClientsMap.remove(vaultId); + } + @Override protected void onCredentialsUpdated(Credentials credentials) throws SkyflowException { for (VaultController vault : this.vaultClientsMap.values()) { From 1b6f88c6f5ebf5d1351b765225a5b4213d226be6 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Mon, 20 Jul 2026 09:34:08 +0530 Subject: [PATCH 23/28] SK-2967 fix compile errors --- .../java/com/skyflow/BaseSkyflowTests.java | 19 +++++++++++++-- .../com/skyflow/BaseVaultClientTests.java | 23 ++++++++++--------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/common/src/test/java/com/skyflow/BaseSkyflowTests.java b/common/src/test/java/com/skyflow/BaseSkyflowTests.java index 57c72a83..2859a744 100644 --- a/common/src/test/java/com/skyflow/BaseSkyflowTests.java +++ b/common/src/test/java/com/skyflow/BaseSkyflowTests.java @@ -260,9 +260,12 @@ public void testMergeVaultConfigWithNullClusterIdFallsBackToPreviousClusterId() Assert.assertEquals(clusterID, result.getClusterId()); } - private static class TestSkyflow extends BaseSkyflow { + private static class TestSkyflow extends BaseSkyflow { + private final TestSkyflowClientBuilder builder; + private TestSkyflow(TestSkyflowClientBuilder builder) { super(builder); + this.builder = builder; } static TestSkyflowClientBuilder builder() { @@ -274,12 +277,19 @@ protected TestSkyflow self() { return this; } + Object vault() throws SkyflowException { + return resolveOrThrow(this.builder.vaultClientsMap, null, + ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); + } + Object vault(String vaultId) throws SkyflowException { return resolveOrThrow(this.builder.vaultClientsMap, vaultId, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList); } - private static class TestSkyflowClientBuilder extends BaseSkyflowClientBuilder { + private static class TestSkyflowClientBuilder extends BaseSkyflowClientBuilder { + private final java.util.LinkedHashMap vaultClientsMap = new java.util.LinkedHashMap<>(); + @Override protected void validateVaultConfig(BaseVaultConfig vaultConfig) throws SkyflowException { if (vaultConfig.getVaultId() == null || vaultConfig.getVaultId().trim().isEmpty()) { @@ -297,6 +307,11 @@ protected void onVaultConfigUpdated(BaseVaultConfig updatedConfig) { this.vaultClientsMap.put(updatedConfig.getVaultId(), new Object()); } + @Override + protected void onVaultConfigRemoved(String vaultId) { + this.vaultClientsMap.remove(vaultId); + } + @Override protected void onCredentialsUpdated(Credentials credentials) { // no-op: this test double only exercises template orchestration, not propagation diff --git a/common/src/test/java/com/skyflow/BaseVaultClientTests.java b/common/src/test/java/com/skyflow/BaseVaultClientTests.java index e5a12687..c8c128f2 100644 --- a/common/src/test/java/com/skyflow/BaseVaultClientTests.java +++ b/common/src/test/java/com/skyflow/BaseVaultClientTests.java @@ -1,6 +1,7 @@ package com.skyflow; import com.skyflow.config.BaseCredentials; +import com.skyflow.config.BaseVaultConfig; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.utils.BaseConstants; @@ -35,15 +36,15 @@ public void restoreEnvFile() throws IOException { } } - private BaseVaultClient newClient(BaseCredentials commonCredentials) { - return new BaseVaultClient<>(new Object(), commonCredentials); + private BaseVaultClient newClient(BaseCredentials commonCredentials) { + return new BaseVaultClient<>(new BaseVaultConfig(), commonCredentials); } @Test public void testPrioritiseCredentials_prefersVaultSpecificCredentials() throws SkyflowException { BaseCredentials vaultSpecific = new BaseCredentials(); vaultSpecific.setApiKey("test_api_key"); - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); client.prioritiseCredentials(vaultSpecific); @@ -54,7 +55,7 @@ public void testPrioritiseCredentials_prefersVaultSpecificCredentials() throws S public void testPrioritiseCredentials_fallsBackToCommonCredentials() throws SkyflowException { BaseCredentials common = new BaseCredentials(); common.setApiKey("common_api_key"); - BaseVaultClient client = newClient(common); + BaseVaultClient client = newClient(common); client.prioritiseCredentials(null); @@ -65,7 +66,7 @@ public void testPrioritiseCredentials_fallsBackToCommonCredentials() throws Skyf public void testPrioritiseCredentials_credentialChange_resetsTokenAndApiKey() throws SkyflowException { BaseCredentials credentialsA = new BaseCredentials(); credentialsA.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); client.prioritiseCredentials(credentialsA); client.token = "cached-token"; @@ -83,7 +84,7 @@ public void testPrioritiseCredentials_credentialChange_resetsTokenAndApiKey() th public void testSetBearerToken_withApiKey() throws SkyflowException { BaseCredentials creds = new BaseCredentials(); creds.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); client.setBearerToken(creds); @@ -94,7 +95,7 @@ public void testSetBearerToken_withApiKey() throws SkyflowException { public void testSetBearerToken_generatesTokenWhenNull() throws SkyflowException { BaseCredentials creds = new BaseCredentials(); creds.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); client.setBearerToken(creds); @@ -105,7 +106,7 @@ public void testSetBearerToken_generatesTokenWhenNull() throws SkyflowException public void testSetBearerToken_reusesValidNonExpiredToken() throws SkyflowException { BaseCredentials creds = new BaseCredentials(); creds.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); // First call: token=null → generates from creds.getToken() client.setBearerToken(creds); @@ -118,7 +119,7 @@ public void testSetBearerToken_reusesValidNonExpiredToken() throws SkyflowExcept @Test public void testSetBearerToken_noCredentials_throwsEmptyCredentials() { - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); try { client.setBearerToken(null); Assert.fail("Should have thrown SkyflowException"); @@ -137,7 +138,7 @@ public void testPrioritiseCredentials_dotenvReturnsCredentials_setsCredentials() fw.write(BaseConstants.ENV_CREDENTIALS_KEY_NAME + "={\"token\":\"env-token-value\"}\n"); } - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); client.prioritiseCredentials(null); Assert.assertNotNull(client.finalCredentials); @@ -154,7 +155,7 @@ public void testPrioritiseCredentials_dotenvKeyMissing_throwsSkyflowException() fw.write("SOME_OTHER_KEY=some_value\n"); } - BaseVaultClient client = newClient(null); + BaseVaultClient client = newClient(null); try { client.prioritiseCredentials(null); Assert.fail("Should have thrown SkyflowException"); From 073e6304106d9d1a4a1b3ea6fa2c31acf3d2061d Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Mon, 20 Jul 2026 19:12:44 +0530 Subject: [PATCH 24/28] SK-2967 fix compile errors --- common/src/main/java/com/skyflow/BaseSkyflow.java | 8 +++++--- common/src/test/java/com/skyflow/BaseSkyflowTests.java | 5 +++++ flowvault/src/main/java/com/skyflow/Skyflow.java | 5 +++++ v2/src/main/java/com/skyflow/Skyflow.java | 5 +++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java index f752fdfd..7475012d 100644 --- a/common/src/main/java/com/skyflow/BaseSkyflow.java +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -117,7 +117,7 @@ protected final void addVaultConfigTemplate(V vaultConfig) throws SkyflowExcepti validateVaultConfig(vaultConfig); V vaultConfigCopy = cloneVaultConfig(vaultConfig); String vaultId = extractVaultId(vaultConfigCopy); - if (this.vaultConfigMap.containsKey(vaultId)) { + if (hasVaultClient(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString( ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultId )); @@ -132,7 +132,7 @@ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowExce LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog()); validateVaultConfig(vaultConfig); String vaultId = extractVaultId(vaultConfig); - if (!this.vaultConfigMap.containsKey(vaultId)) { + if (!hasVaultClient(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString( ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId )); @@ -144,7 +144,7 @@ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowExce } protected final void removeVaultConfigTemplate(String vaultId) throws SkyflowException { - if (!this.vaultConfigMap.containsKey(vaultId)) { + if (!hasVaultClient(vaultId)) { LogUtil.printErrorLog(BaseUtils.parameterizedString(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId)); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); } @@ -166,6 +166,8 @@ protected final void addSkyflowCredentialsTemplate(Credentials credentials) thro protected abstract void validateVaultConfig(V vaultConfig) throws SkyflowException; + protected abstract boolean hasVaultClient(String vaultId); + @SuppressWarnings("unchecked") protected final V cloneVaultConfig(V vaultConfig) { try { diff --git a/common/src/test/java/com/skyflow/BaseSkyflowTests.java b/common/src/test/java/com/skyflow/BaseSkyflowTests.java index 2859a744..12ae256c 100644 --- a/common/src/test/java/com/skyflow/BaseSkyflowTests.java +++ b/common/src/test/java/com/skyflow/BaseSkyflowTests.java @@ -312,6 +312,11 @@ protected void onVaultConfigRemoved(String vaultId) { this.vaultClientsMap.remove(vaultId); } + @Override + protected boolean hasVaultClient(String vaultId) { + return this.vaultClientsMap.containsKey(vaultId); + } + @Override protected void onCredentialsUpdated(Credentials credentials) { // no-op: this test double only exercises template orchestration, not propagation diff --git a/flowvault/src/main/java/com/skyflow/Skyflow.java b/flowvault/src/main/java/com/skyflow/Skyflow.java index 61a95f9a..96b5f45a 100644 --- a/flowvault/src/main/java/com/skyflow/Skyflow.java +++ b/flowvault/src/main/java/com/skyflow/Skyflow.java @@ -68,6 +68,11 @@ protected void onVaultConfigRemoved(String vaultId) throws SkyflowException { this.vaultClientsMap.remove(vaultId); } + @Override + protected boolean hasVaultClient(String vaultId) { + return this.vaultClientsMap.containsKey(vaultId); + } + @Override protected void onCredentialsUpdated(Credentials credentials) throws SkyflowException { for (VaultController vault : this.vaultClientsMap.values()) { diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index 16614481..2daf9b27 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -114,6 +114,11 @@ protected void onVaultConfigRemoved(String vaultId) throws SkyflowException { this.vaultClientsMap.remove(vaultId); } + @Override + protected boolean hasVaultClient(String vaultId) { + return this.vaultClientsMap.containsKey(vaultId); + } + @Override protected void onCredentialsUpdated(Credentials credentials) throws SkyflowException { for (VaultController vault : this.vaultClientsMap.values()) { From 64d51ef5a00964d25f55edee9afbc105db31d920 Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Mon, 20 Jul 2026 20:49:11 +0530 Subject: [PATCH 25/28] SK-2967 revert generated code --- .../com/skyflow/generated/rest/ApiClient.java | 1 + .../generated/rest/AsyncApiClient.java | 1 + .../generated/rest/core/ClientOptions.java | 2 +- .../generated/rest/core/FileStream.java | 5 +- .../rest/core/InputStreamRequestBody.java | 7 +- .../generated/rest/core/ObjectMappers.java | 1 + .../rest/core/QueryStringMapper.java | 7 +- .../rest/core/ResponseBodyInputStream.java | 3 +- .../rest/core/ResponseBodyReader.java | 3 +- .../generated/rest/core/RetryInterceptor.java | 5 +- .../rest/errors/BadRequestError.java | 9 +- .../rest/errors/UnauthorizedError.java | 9 +- .../resources/audit/AsyncRawAuditClient.java | 20 +-- .../rest/resources/audit/RawAuditClient.java | 16 +-- .../AuditServiceListAuditEventsRequest.java | 18 +-- .../binlookup/AsyncRawBinLookupClient.java | 21 +-- .../binlookup/RawBinLookupClient.java | 17 +-- .../binlookup/requests/V1BinListRequest.java | 15 +-- .../resources/files/AsyncFilesClient.java | 13 +- .../resources/files/AsyncRawFilesClient.java | 78 ++++------- .../rest/resources/files/FilesClient.java | 12 +- .../rest/resources/files/RawFilesClient.java | 74 ++++------- ...entifyFileAudioRequestDeidentifyAudio.java | 15 +-- ...fyFileDocumentPdfRequestDeidentifyPdf.java | 15 +-- ...entifyFileImageRequestDeidentifyImage.java | 15 +-- .../files/requests/DeidentifyFileRequest.java | 15 +-- ...identifyFileRequestDeidentifyDocument.java | 15 +-- ...tifyFileRequestDeidentifyPresentation.java | 15 +-- ...ntifyFileRequestDeidentifySpreadsheet.java | 15 +-- ...fyFileRequestDeidentifyStructuredText.java | 15 +-- .../DeidentifyFileRequestDeidentifyText.java | 15 +-- .../files/requests/GetRunRequest.java | 9 +- .../ReidentifyFileRequestReidentifyFile.java | 11 +- .../guardrails/AsyncRawGuardrailsClient.java | 25 +--- .../guardrails/RawGuardrailsClient.java | 21 +-- .../requests/DetectGuardrailsRequest.java | 15 +-- .../resources/query/AsyncRawQueryClient.java | 21 +-- .../rest/resources/query/RawQueryClient.java | 17 +-- .../QueryServiceExecuteQueryBody.java | 9 +- .../records/AsyncRawRecordsClient.java | 49 ++----- .../resources/records/AsyncRecordsClient.java | 21 +-- .../resources/records/RawRecordsClient.java | 45 +------ .../rest/resources/records/RecordsClient.java | 21 +-- .../FileServiceUploadFileRequest.java | 9 +- .../RecordServiceBatchOperationBody.java | 15 +-- .../RecordServiceBulkDeleteRecordBody.java | 15 +-- .../RecordServiceBulkGetRecordRequest.java | 16 +-- .../RecordServiceGetRecordRequest.java | 16 +-- .../RecordServiceInsertRecordBody.java | 15 +-- .../RecordServiceUpdateRecordBody.java | 9 +- .../records/requests/UploadFileV2Request.java | 11 +- .../strings/AsyncRawStringsClient.java | 29 ++-- .../resources/strings/RawStringsClient.java | 25 +--- .../requests/DeidentifyStringRequest.java | 15 +-- .../requests/ReidentifyStringRequest.java | 9 +- .../tokens/AsyncRawTokensClient.java | 21 +-- .../resources/tokens/AsyncTokensClient.java | 1 + .../resources/tokens/RawTokensClient.java | 17 +-- .../tokens/requests/V1DetokenizePayload.java | 15 +-- .../tokens/requests/V1TokenizePayload.java | 15 +-- .../rest/types/AuditEventContext.java | 9 +- .../generated/rest/types/AuditEventData.java | 9 +- .../rest/types/AuditEventHttpInfo.java | 9 +- .../rest/types/DeidentifiedFileOutput.java | 9 +- .../rest/types/DeidentifyFileResponse.java | 9 +- .../rest/types/DeidentifyStringResponse.java | 15 +-- .../rest/types/DetectGuardrailsResponse.java | 11 +- .../rest/types/DetectRunsResponse.java | 15 +-- .../generated/rest/types/ErrorResponse.java | 10 +- .../rest/types/ErrorResponseError.java | 15 +-- .../generated/rest/types/FileData.java | 10 +- .../rest/types/FileDataDeidentifyAudio.java | 10 +- .../types/FileDataDeidentifyDocument.java | 10 +- .../rest/types/FileDataDeidentifyImage.java | 10 +- .../rest/types/FileDataDeidentifyPdf.java | 10 +- .../types/FileDataDeidentifyPresentation.java | 10 +- .../types/FileDataDeidentifySpreadsheet.java | 10 +- .../FileDataDeidentifyStructuredText.java | 10 +- .../rest/types/FileDataDeidentifyText.java | 10 +- .../rest/types/FileDataReidentifyFile.java | 10 +- .../skyflow/generated/rest/types/Format.java | 15 +-- .../generated/rest/types/GooglerpcStatus.java | 15 +-- .../rest/types/IdentifyResponse.java | 10 +- .../generated/rest/types/Locations.java | 9 +- .../generated/rest/types/ProtobufAny.java | 9 +- .../rest/types/ReidentifiedFileOutput.java | 9 +- .../rest/types/ReidentifyFileResponse.java | 9 +- .../generated/rest/types/ShiftDates.java | 15 +-- .../rest/types/StringResponseEntities.java | 9 +- .../rest/types/TokenTypeMapping.java | 15 +-- .../generated/rest/types/Transformations.java | 9 +- .../rest/types/UploadFileV2Response.java | 9 +- .../rest/types/V1AuditAfterOptions.java | 9 +- .../rest/types/V1AuditEventResponse.java | 9 +- .../generated/rest/types/V1AuditResponse.java | 15 +-- .../rest/types/V1AuditResponseEvent.java | 15 +-- .../types/V1AuditResponseEventRequest.java | 15 +-- .../rest/types/V1BatchOperationResponse.java | 15 +-- .../generated/rest/types/V1BatchRecord.java | 9 +- .../rest/types/V1BinListResponse.java | 15 +-- .../types/V1BulkDeleteRecordResponse.java | 15 +-- .../rest/types/V1BulkGetRecordResponse.java | 15 +-- .../skyflow/generated/rest/types/V1Card.java | 9 +- .../rest/types/V1DeleteFileResponse.java | 9 +- .../rest/types/V1DeleteRecordResponse.java | 9 +- .../rest/types/V1DetokenizeRecordRequest.java | 9 +- .../types/V1DetokenizeRecordResponse.java | 9 +- .../rest/types/V1DetokenizeResponse.java | 15 +-- .../generated/rest/types/V1FieldRecords.java | 9 +- .../rest/types/V1GetAuthTokenResponse.java | 125 ++++++++++++++++++ .../types/V1GetFileScanStatusResponse.java | 9 +- .../rest/types/V1GetQueryResponse.java | 15 +-- .../rest/types/V1InsertRecordResponse.java | 15 +-- .../rest/types/V1RecordMetaProperties.java | 9 +- .../rest/types/V1TokenizeRecordRequest.java | 9 +- .../rest/types/V1TokenizeRecordResponse.java | 9 +- .../rest/types/V1TokenizeResponse.java | 15 +-- .../rest/types/V1UpdateRecordResponse.java | 9 +- .../rest/types/V1VaultFieldMapping.java | 9 +- .../rest/types/V1VaultSchemaConfig.java | 9 +- .../rest/types/WordCharacterCount.java | 9 +- 121 files changed, 513 insertions(+), 1263 deletions(-) create mode 100644 v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java diff --git a/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java b/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java index cd305df1..ab81f443 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/ApiClient.java @@ -13,6 +13,7 @@ import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.generated.rest.resources.strings.StringsClient; import com.skyflow.generated.rest.resources.tokens.TokensClient; + import java.util.function.Supplier; public class ApiClient { diff --git a/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java b/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java index f0ca2c05..dc57df06 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java @@ -13,6 +13,7 @@ import com.skyflow.generated.rest.resources.records.AsyncRecordsClient; import com.skyflow.generated.rest.resources.strings.AsyncStringsClient; import com.skyflow.generated.rest.resources.tokens.AsyncTokensClient; + import java.util.function.Supplier; public class AsyncApiClient { diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java b/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java index 2a5f0710..da41fb25 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java @@ -35,7 +35,7 @@ private ClientOptions( { put("X-Fern-Language", "JAVA"); put("X-Fern-SDK-Name", "com.skyflow.fern:api-sdk"); - put("X-Fern-SDK-Version", "0.0.98"); + put("X-Fern-SDK-Version", "0.0.385"); } }); this.headerSuppliers = headerSuppliers; diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java b/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java index 6b459431..2131b0a4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/FileStream.java @@ -3,12 +3,13 @@ */ package com.skyflow.generated.rest.core; -import java.io.InputStream; -import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; import org.jetbrains.annotations.Nullable; +import java.io.InputStream; +import java.util.Objects; + /** * Represents a file stream with associated metadata for file uploads. */ diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java b/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java index 545f6088..55c3c971 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java @@ -3,9 +3,6 @@ */ package com.skyflow.generated.rest.core; -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.internal.Util; @@ -14,6 +11,10 @@ import okio.Source; import org.jetbrains.annotations.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; + /** * A custom implementation of OkHttp's RequestBody that wraps an InputStream. * This class allows streaming of data from an InputStream directly to an HTTP request body, diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java b/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java index 3b7894e0..acec32b4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + import java.io.IOException; public final class ObjectMappers { diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java b/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java index e9e18fb9..c0687736 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java @@ -7,14 +7,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; import okhttp3.HttpUrl; import okhttp3.MultipartBody; +import java.util.*; + public class QueryStringMapper { private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER; diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java index d8df7715..1bb0b5dc 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java @@ -3,9 +3,10 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Response; + import java.io.FilterInputStream; import java.io.IOException; -import okhttp3.Response; /** * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java index ed894407..e6c1a525 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java @@ -3,9 +3,10 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Response; + import java.io.FilterReader; import java.io.IOException; -import okhttp3.Response; /** * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the diff --git a/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java b/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java index eda7d265..7a28c3c9 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java +++ b/v2/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java @@ -3,12 +3,13 @@ */ package com.skyflow.generated.rest.core; +import okhttp3.Interceptor; +import okhttp3.Response; + import java.io.IOException; import java.time.Duration; import java.util.Optional; import java.util.Random; -import okhttp3.Interceptor; -import okhttp3.Response; public class RetryInterceptor implements Interceptor { diff --git a/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java index 02c36c4b..80ae5e7c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java +++ b/v2/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java @@ -4,21 +4,20 @@ package com.skyflow.generated.rest.errors; import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.types.ErrorResponse; import okhttp3.Response; public final class BadRequestError extends ApiClientApiException { /** * The body of the response that triggered the exception. */ - private final ErrorResponse body; + private final Object body; - public BadRequestError(ErrorResponse body) { + public BadRequestError(Object body) { super("BadRequestError", 400, body); this.body = body; } - public BadRequestError(ErrorResponse body, Response rawResponse) { + public BadRequestError(Object body, Response rawResponse) { super("BadRequestError", 400, body, rawResponse); this.body = body; } @@ -27,7 +26,7 @@ public BadRequestError(ErrorResponse body, Response rawResponse) { * @return the body */ @Override - public ErrorResponse body() { + public Object body() { return this.body; } } diff --git a/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java b/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java index 00ddc4ce..3bc254bc 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java +++ b/v2/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java @@ -4,21 +4,20 @@ package com.skyflow.generated.rest.errors; import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.types.ErrorResponse; import okhttp3.Response; public final class UnauthorizedError extends ApiClientApiException { /** * The body of the response that triggered the exception. */ - private final ErrorResponse body; + private final Object body; - public UnauthorizedError(ErrorResponse body) { + public UnauthorizedError(Object body) { super("UnauthorizedError", 401, body); this.body = body; } - public UnauthorizedError(ErrorResponse body, Response rawResponse) { + public UnauthorizedError(Object body, Response rawResponse) { super("UnauthorizedError", 401, body, rawResponse); this.body = body; } @@ -27,7 +26,7 @@ public UnauthorizedError(ErrorResponse body, Response rawResponse) { * @return the body */ @Override - public ErrorResponse body() { + public Object body() { return this.body; } } diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java index 875ca259..e1516eaf 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/AsyncRawAuditClient.java @@ -4,27 +4,15 @@ package com.skyflow.generated.rest.resources.audit; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.audit.requests.AuditServiceListAuditEventsRequest; import com.skyflow.generated.rest.types.V1AuditResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawAuditClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java index bfec3bf2..68cd5e3b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/RawAuditClient.java @@ -4,23 +4,13 @@ package com.skyflow.generated.rest.resources.audit; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.audit.requests.AuditServiceListAuditEventsRequest; import com.skyflow.generated.rest.types.V1AuditResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawAuditClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java index 8b6686e4..e9f8cf12 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/audit/requests/AuditServiceListAuditEventsRequest.java @@ -3,26 +3,16 @@ */ package com.skyflow.generated.rest.resources.audit.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsActionType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextAccessType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextActorType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsContextAuthMode; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestFilterOpsResourceType; -import com.skyflow.generated.rest.resources.audit.types.AuditServiceListAuditEventsRequestSortOpsOrderBy; +import com.skyflow.generated.rest.resources.audit.types.*; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = AuditServiceListAuditEventsRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java index 2a3f5f4f..9cf03c7d 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/AsyncRawBinLookupClient.java @@ -4,28 +4,15 @@ package com.skyflow.generated.rest.resources.binlookup; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.binlookup.requests.V1BinListRequest; import com.skyflow.generated.rest.types.V1BinListResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawBinLookupClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java index bb08039b..21e77017 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/RawBinLookupClient.java @@ -4,24 +4,13 @@ package com.skyflow.generated.rest.resources.binlookup; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.binlookup.requests.V1BinListRequest; import com.skyflow.generated.rest.types.V1BinListResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawBinLookupClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java index af827e01..def40293 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/binlookup/requests/V1BinListRequest.java @@ -3,21 +3,12 @@ */ package com.skyflow.generated.rest.resources.binlookup.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1VaultSchemaConfig; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BinListRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java index 1f157223..01031423 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java @@ -5,20 +5,11 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; + import java.util.concurrent.CompletableFuture; public class AsyncFilesClient { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java index f497bb02..e7f008e8 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java @@ -4,44 +4,20 @@ package com.skyflow.generated.rest.resources.files; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawFilesClient { protected final ClientOptions clientOptions; @@ -102,12 +78,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -190,12 +166,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -278,12 +254,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -366,12 +342,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -454,12 +430,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -542,12 +518,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -630,12 +606,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -718,12 +694,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -806,12 +782,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -894,12 +870,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -983,12 +959,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java index 8d083d76..bcda96e6 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java @@ -5,17 +5,7 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java index 0d44668e..d277d224 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java @@ -4,40 +4,18 @@ package com.skyflow.generated.rest.resources.files; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileAudioRequestDeidentifyAudio; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileDocumentPdfRequestDeidentifyPdf; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileImageRequestDeidentifyImage; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyDocument; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyPresentation; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifySpreadsheet; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyStructuredText; -import com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequestDeidentifyText; -import com.skyflow.generated.rest.resources.files.requests.GetRunRequest; -import com.skyflow.generated.rest.resources.files.requests.ReidentifyFileRequestReidentifyFile; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.types.DeidentifyFileResponse; import com.skyflow.generated.rest.types.DetectRunsResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.ReidentifyFileResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawFilesClient { protected final ClientOptions clientOptions; @@ -92,10 +70,10 @@ public ApiClientHttpResponse deidentifyFile( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -160,10 +138,10 @@ public ApiClientHttpResponse deidentifyAudio( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -228,10 +206,10 @@ public ApiClientHttpResponse deidentifyDocument( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -296,10 +274,10 @@ public ApiClientHttpResponse deidentifyPdf( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -364,10 +342,10 @@ public ApiClientHttpResponse deidentifyImage( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -432,10 +410,10 @@ public ApiClientHttpResponse deidentifyPresentation( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -500,10 +478,10 @@ public ApiClientHttpResponse deidentifySpreadsheet( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -568,10 +546,10 @@ public ApiClientHttpResponse deidentifyStructuredText( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -635,10 +613,10 @@ public ApiClientHttpResponse deidentifyText( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -702,10 +680,10 @@ public ApiClientHttpResponse reidentifyFile( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -771,10 +749,10 @@ public ApiClientHttpResponse getRun( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java index d1cadca3..c2baa931 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileAudioRequestDeidentifyAudio.java @@ -3,13 +3,7 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem; @@ -17,13 +11,10 @@ import com.skyflow.generated.rest.types.FileDataDeidentifyAudio; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileAudioRequestDeidentifyAudio.Builder.class) public final class DeidentifyFileAudioRequestDeidentifyAudio { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java index 5b6a653f..1844a116 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileDocumentPdfRequestDeidentifyPdf.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyPdf; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileDocumentPdfRequestDeidentifyPdf.Builder.class) public final class DeidentifyFileDocumentPdfRequestDeidentifyPdf { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java index 015bba9e..25ddea9c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileImageRequestDeidentifyImage.java @@ -3,13 +3,7 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileImageRequestDeidentifyImageEntityTypesItem; @@ -17,13 +11,10 @@ import com.skyflow.generated.rest.types.FileDataDeidentifyImage; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileImageRequestDeidentifyImage.Builder.class) public final class DeidentifyFileImageRequestDeidentifyImage { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java index c2cdcfb5..62d77229 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequest.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestEntityTypesItem; import com.skyflow.generated.rest.types.FileData; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequest.Builder.class) public final class DeidentifyFileRequest { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java index fc3db52a..c4d9841d 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyDocument.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyDocumentEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyDocument; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyDocument.Builder.class) public final class DeidentifyFileRequestDeidentifyDocument { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java index f45802ec..e1cea77f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyPresentation.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyPresentationEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyPresentation; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyPresentation.Builder.class) public final class DeidentifyFileRequestDeidentifyPresentation { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java index 93ea921a..10ca8feb 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifySpreadsheet.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifySpreadsheet; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifySpreadsheet.Builder.class) public final class DeidentifyFileRequestDeidentifySpreadsheet { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java index b579fe1b..e3f555b8 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyStructuredText.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyStructuredText; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyStructuredText.Builder.class) public final class DeidentifyFileRequestDeidentifyStructuredText { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java index 7a7c6615..8457c790 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/DeidentifyFileRequestDeidentifyText.java @@ -3,26 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.files.types.DeidentifyFileRequestDeidentifyTextEntityTypesItem; import com.skyflow.generated.rest.types.FileDataDeidentifyText; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyFileRequestDeidentifyText.Builder.class) public final class DeidentifyFileRequestDeidentifyText { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java index 490392f1..cde24227 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/GetRunRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java index 0f5e79ab..5cd22747 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/files/requests/ReidentifyFileRequestReidentifyFile.java @@ -3,22 +3,17 @@ */ package com.skyflow.generated.rest.resources.files.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.FileDataReidentifyFile; import com.skyflow.generated.rest.types.Format; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ReidentifyFileRequestReidentifyFile.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java index 28829a68..80853472 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/AsyncRawGuardrailsClient.java @@ -4,31 +4,18 @@ package com.skyflow.generated.rest.resources.guardrails; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; import com.skyflow.generated.rest.resources.guardrails.requests.DetectGuardrailsRequest; import com.skyflow.generated.rest.types.DetectGuardrailsResponse; import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawGuardrailsClient { protected final ClientOptions clientOptions; @@ -89,12 +76,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java index bdf632ca..5bf5c31a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/RawGuardrailsClient.java @@ -4,27 +4,16 @@ package com.skyflow.generated.rest.resources.guardrails; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; import com.skyflow.generated.rest.resources.guardrails.requests.DetectGuardrailsRequest; import com.skyflow.generated.rest.types.DetectGuardrailsResponse; import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawGuardrailsClient { protected final ClientOptions clientOptions; @@ -79,10 +68,10 @@ public ApiClientHttpResponse checkGuardrails( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java index 9063fed8..75250f8c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/guardrails/requests/DetectGuardrailsRequest.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.resources.guardrails.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectGuardrailsRequest.Builder.class) public final class DetectGuardrailsRequest { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java index 96e2dc0b..7b8c9383 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java @@ -4,28 +4,15 @@ package com.skyflow.generated.rest.resources.query; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.types.V1GetQueryResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawQueryClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java index 3e5bee51..ec88ae93 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java @@ -4,24 +4,13 @@ package com.skyflow.generated.rest.resources.query; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.types.V1GetQueryResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawQueryClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java index 60565eb5..000cd685 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/query/requests/QueryServiceExecuteQueryBody.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.resources.query.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java index 8840b51c..b1c9ae18 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java @@ -4,54 +4,21 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.ErrorResponse; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.MultipartBody; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawRecordsClient { protected final ClientOptions clientOptions; @@ -1022,12 +989,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 404: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java index c6925b50..ed7240c9 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java @@ -5,24 +5,9 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; + import java.io.File; import java.util.Optional; import java.util.concurrent.CompletableFuture; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java index 977e84bb..29530b56 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java @@ -4,50 +4,19 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.QueryStringMapper; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.errors.UnauthorizedError; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.ErrorResponse; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; +import okhttp3.*; + import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Optional; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.MultipartBody; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawRecordsClient { protected final ClientOptions clientOptions; @@ -862,10 +831,10 @@ public ApiClientHttpResponse uploadFileV2( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 404: throw new NotFoundError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java index 7b4599c6..eb9bc81d 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java @@ -5,24 +5,9 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.requests.FileServiceUploadFileRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceGetRecordRequest; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; -import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; -import com.skyflow.generated.rest.resources.records.requests.UploadFileV2Request; -import com.skyflow.generated.rest.types.UploadFileV2Response; -import com.skyflow.generated.rest.types.V1BatchOperationResponse; -import com.skyflow.generated.rest.types.V1BulkDeleteRecordResponse; -import com.skyflow.generated.rest.types.V1BulkGetRecordResponse; -import com.skyflow.generated.rest.types.V1DeleteFileResponse; -import com.skyflow.generated.rest.types.V1DeleteRecordResponse; -import com.skyflow.generated.rest.types.V1FieldRecords; -import com.skyflow.generated.rest.types.V1GetFileScanStatusResponse; -import com.skyflow.generated.rest.types.V1InsertRecordResponse; -import com.skyflow.generated.rest.types.V1UpdateRecordResponse; +import com.skyflow.generated.rest.resources.records.requests.*; +import com.skyflow.generated.rest.types.*; + import java.io.File; import java.util.Optional; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java index fe805970..3efb0a98 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/FileServiceUploadFileRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java index 48586839..c1997213 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBatchOperationBody.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1BatchRecord; import com.skyflow.generated.rest.types.V1Byot; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBatchOperationBody.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java index b417adbb..4b9dcced 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkDeleteRecordBody.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBulkDeleteRecordBody.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java index 22c9090c..9b59168a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceBulkGetRecordRequest.java @@ -3,23 +3,13 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.records.types.RecordServiceBulkGetRecordRequestOrderBy; import com.skyflow.generated.rest.resources.records.types.RecordServiceBulkGetRecordRequestRedaction; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceBulkGetRecordRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java index eef17665..91317d02 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceGetRecordRequest.java @@ -3,22 +3,12 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.records.types.RecordServiceGetRecordRequestRedaction; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceGetRecordRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java index e1de00f7..e832e396 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceInsertRecordBody.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1Byot; import com.skyflow.generated.rest.types.V1FieldRecords; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = RecordServiceInsertRecordBody.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java index e52af2e4..f5c7a229 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/RecordServiceUpdateRecordBody.java @@ -3,17 +3,12 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1Byot; import com.skyflow.generated.rest.types.V1FieldRecords; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java index f162530c..81a9f837 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/records/requests/UploadFileV2Request.java @@ -3,20 +3,15 @@ */ package com.skyflow.generated.rest.resources.records.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = UploadFileV2Request.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java index aed19530..36b364b5 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/AsyncRawStringsClient.java @@ -4,13 +4,7 @@ package com.skyflow.generated.rest.resources.strings; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; @@ -19,18 +13,11 @@ import com.skyflow.generated.rest.types.DeidentifyStringResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.IdentifyResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawStringsClient { protected final ClientOptions clientOptions; @@ -91,12 +78,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: @@ -185,12 +172,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO switch (response.code()) { case 400: future.completeExceptionally(new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 401: future.completeExceptionally(new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response)); return; case 500: diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java index 560e1931..da6bec56 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/RawStringsClient.java @@ -4,13 +4,7 @@ package com.skyflow.generated.rest.resources.strings; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.BadRequestError; import com.skyflow.generated.rest.errors.InternalServerError; import com.skyflow.generated.rest.errors.UnauthorizedError; @@ -19,14 +13,9 @@ import com.skyflow.generated.rest.types.DeidentifyStringResponse; import com.skyflow.generated.rest.types.ErrorResponse; import com.skyflow.generated.rest.types.IdentifyResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawStringsClient { protected final ClientOptions clientOptions; @@ -81,10 +70,10 @@ public ApiClientHttpResponse deidentifyString( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); @@ -154,10 +143,10 @@ public ApiClientHttpResponse reidentifyString( switch (response.code()) { case 400: throw new BadRequestError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 401: throw new UnauthorizedError( - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); case 500: throw new InternalServerError( ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java index 943ddde4..06ec6cec 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/DeidentifyStringRequest.java @@ -3,25 +3,16 @@ */ package com.skyflow.generated.rest.resources.strings.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.resources.strings.types.DeidentifyStringRequestEntityTypesItem; import com.skyflow.generated.rest.types.TokenTypeMapping; import com.skyflow.generated.rest.types.Transformations; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyStringRequest.Builder.class) public final class DeidentifyStringRequest { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java index 59c1aaf2..3c42390c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/strings/requests/ReidentifyStringRequest.java @@ -3,16 +3,11 @@ */ package com.skyflow.generated.rest.resources.strings.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.Format; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java index fbf69580..794035bd 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java @@ -4,30 +4,17 @@ package com.skyflow.generated.rest.resources.tokens; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.concurrent.CompletableFuture; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.NotNull; public class AsyncRawTokensClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java index 26d5ea05..621701af 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java @@ -9,6 +9,7 @@ import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; + import java.util.concurrent.CompletableFuture; public class AsyncTokensClient { diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java index 5ed17d28..7ad69d11 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java @@ -4,26 +4,15 @@ package com.skyflow.generated.rest.resources.tokens; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.core.ApiClientException; -import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.MediaTypes; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.*; import com.skyflow.generated.rest.errors.NotFoundError; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.V1DetokenizeResponse; import com.skyflow.generated.rest.types.V1TokenizeResponse; +import okhttp3.*; + import java.io.IOException; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; public class RawTokensClient { protected final ClientOptions clientOptions; diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java index 59318aa8..52571f64 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1DetokenizePayload.java @@ -3,21 +3,12 @@ */ package com.skyflow.generated.rest.resources.tokens.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1DetokenizeRecordRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1DetokenizePayload.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java index 9729023e..e5fc08f4 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java +++ b/v2/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/V1TokenizePayload.java @@ -3,21 +3,12 @@ */ package com.skyflow.generated.rest.resources.tokens.requests; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.generated.rest.types.V1TokenizeRecordRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1TokenizePayload.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java index 210f96c0..73aed9c1 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventContext.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java index e2028fba..bab4b42a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventData.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java index 1352c42f..9d3bbaed 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/AuditEventHttpInfo.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java index a7dd7c68..dc244be8 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifiedFileOutput.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java index d2b8e5b6..d5a2ebd5 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyFileResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java index e831f142..1389fa0f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DeidentifyStringResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DeidentifyStringResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java index 9773dcc3..9cb2d319 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DetectGuardrailsResponse.java @@ -3,20 +3,15 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectGuardrailsResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java index c97f7635..b73f7845 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/DetectRunsResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = DetectRunsResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java index 565714eb..4113b998 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ErrorResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java index bcc23f03..4774fa57 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java @@ -3,22 +3,13 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import org.jetbrains.annotations.NotNull; +import java.util.*; + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ErrorResponseError.Builder.class) public final class ErrorResponseError { diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java index 7f58332e..fd6fa822 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileData.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileData.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java index 2aa88f7b..b6a5ea11 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyAudio.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyAudio.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java index e6390e28..5fb12fba 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyDocument.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyDocument.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java index 127c5f4c..bc5e2c6b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyImage.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyImage.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java index 20b0314f..5606e917 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPdf.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyPdf.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java index e808f0b2..0bedabc5 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyPresentation.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyPresentation.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java index 33478d20..dd017bb8 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifySpreadsheet.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifySpreadsheet.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java index dad188ce..814d51c3 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyStructuredText.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyStructuredText.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java index 79045d7a..e5c88180 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataDeidentifyText.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataDeidentifyText.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java index edea3145..9148703c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/FileDataReidentifyFile.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = FileDataReidentifyFile.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/Format.java b/v2/src/main/java/com/skyflow/generated/rest/types/Format.java index 68ac94ca..1563b90a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/Format.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Format.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = Format.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java b/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java index 807aee4e..55be5699 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/GooglerpcStatus.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = GooglerpcStatus.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java index e7ae30fc..c1bd23c6 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/IdentifyResponse.java @@ -3,18 +3,14 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; +import org.jetbrains.annotations.NotNull; + import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.jetbrains.annotations.NotNull; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = IdentifyResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java b/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java index 9864541a..4b95c485 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Locations.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java b/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java index 9f019b66..40e73b99 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ProtobufAny.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java index b5a4f6f5..a12660cb 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifiedFileOutput.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java index 024200d1..b7bc22ca 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ReidentifyFileResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java b/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java index 2fc4b11a..37ef8cdf 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/ShiftDates.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ShiftDates.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java b/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java index 81c1e58d..78df8838 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/StringResponseEntities.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java index f8c1edb4..b703895d 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/TokenTypeMapping.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = TokenTypeMapping.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java b/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java index 12a5afc7..c9165409 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/Transformations.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java b/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java index c1ddbd58..8f5fea5a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/UploadFileV2Response.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java index d942fdcd..037b80bf 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditAfterOptions.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java index c582d06d..f7ca73f0 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditEventResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java index dd23d77c..36d7ccce 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java index ca2bfdc2..a54eec6c 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEvent.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponseEvent.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java index 046c8fb4..90d9c538 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1AuditResponseEventRequest.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1AuditResponseEventRequest.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java index a557da82..8f5fb775 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchOperationResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BatchOperationResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java index afc572cf..3f0455cc 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BatchRecord.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java index 58472a8b..88c1c125 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BinListResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BinListResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java index ddb0d213..b7151598 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkDeleteRecordResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BulkDeleteRecordResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java index c2d3790a..27878fab 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1BulkGetRecordResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1BulkGetRecordResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java index f2a9db90..ba4f7349 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1Card.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java index 4ec85903..4d9b24eb 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteFileResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java index 2f3bde14..5351d897 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DeleteRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java index 3cf5b59c..b6fb9cb6 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java index ba0abbfa..dd3a9c1f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java index 74f4f6e6..53660cbe 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1DetokenizeResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1DetokenizeResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java index dfbccb8b..b64b8792 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1FieldRecords.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java new file mode 100644 index 00000000..43a86ae0 --- /dev/null +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetAuthTokenResponse.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = V1GetAuthTokenResponse.Builder.class) +public final class V1GetAuthTokenResponse { + private final Optional accessToken; + + private final Optional tokenType; + + private final Map additionalProperties; + + private V1GetAuthTokenResponse( + Optional accessToken, Optional tokenType, Map additionalProperties) { + this.accessToken = accessToken; + this.tokenType = tokenType; + this.additionalProperties = additionalProperties; + } + + /** + * @return AccessToken. + */ + @JsonProperty("accessToken") + public Optional getAccessToken() { + return accessToken; + } + + /** + * @return TokenType : Bearer. + */ + @JsonProperty("tokenType") + public Optional getTokenType() { + return tokenType; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof V1GetAuthTokenResponse && equalTo((V1GetAuthTokenResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(V1GetAuthTokenResponse other) { + return accessToken.equals(other.accessToken) && tokenType.equals(other.tokenType); + } + + @Override + public int hashCode() { + return Objects.hash(this.accessToken, this.tokenType); + } + + @Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional accessToken = Optional.empty(); + + private Optional tokenType = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(V1GetAuthTokenResponse other) { + accessToken(other.getAccessToken()); + tokenType(other.getTokenType()); + return this; + } + + /** + *

AccessToken.

+ */ + @JsonSetter(value = "accessToken", nulls = Nulls.SKIP) + public Builder accessToken(Optional accessToken) { + this.accessToken = accessToken; + return this; + } + + public Builder accessToken(String accessToken) { + this.accessToken = Optional.ofNullable(accessToken); + return this; + } + + /** + *

TokenType : Bearer.

+ */ + @JsonSetter(value = "tokenType", nulls = Nulls.SKIP) + public Builder tokenType(Optional tokenType) { + this.tokenType = tokenType; + return this; + } + + public Builder tokenType(String tokenType) { + this.tokenType = Optional.ofNullable(tokenType); + return this; + } + + public V1GetAuthTokenResponse build() { + return new V1GetAuthTokenResponse(accessToken, tokenType, additionalProperties); + } + } +} diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java index 4bd67013..3138c766 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetFileScanStatusResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java index 821d1f06..a44b0f62 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1GetQueryResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1GetQueryResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java index 0addf786..f8a00001 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1InsertRecordResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java index f69719cf..17f77df6 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1RecordMetaProperties.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java index 2c15ceac..43fe264a 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordRequest.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java index 201a4f60..66721fa1 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java index 62d77bed..05e64bc0 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1TokenizeResponse.java @@ -3,20 +3,11 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; + +import java.util.*; @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = V1TokenizeResponse.Builder.class) diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java index 03ed7b58..d2fcbf1b 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordResponse.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java index c19d1cb5..6fc09854 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultFieldMapping.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java index cd838305..1542ab0f 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/V1VaultSchemaConfig.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; diff --git a/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java b/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java index 594b6d11..314b5942 100644 --- a/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java +++ b/v2/src/main/java/com/skyflow/generated/rest/types/WordCharacterCount.java @@ -3,15 +3,10 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; + import java.util.HashMap; import java.util.Map; import java.util.Objects; From 30628cf0553a37c0698ab046415d0ff27a0b9c1d Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Tue, 21 Jul 2026 09:37:56 +0530 Subject: [PATCH 26/28] SK-2967 improve the issues --- .../main/java/com/skyflow/BaseSkyflow.java | 19 +- .../java/com/skyflow/BaseVaultClient.java | 4 +- .../src/main/java/com/skyflow/ISkyflow.java | 2 +- .../com/skyflow/config/BaseCredentials.java | 11 +- .../java/com/skyflow/errors/ErrorMessage.java | 1 + .../com/skyflow/errors/SkyflowException.java | 2 +- .../main/java/com/skyflow/logs/ErrorLogs.java | 1 + .../java/com/skyflow/utils/BaseUtils.java | 9 +- .../java/com/skyflow/BaseSkyflowTests.java | 2 +- flowvault/dependency-reduced-pom.xml | 195 ++++++++++++++++++ .../main/java/com/skyflow/VaultClient.java | 2 +- .../main/java/com/skyflow/utils/Utils.java | 4 +- .../utils/validations/Validations.java | 12 ++ .../vault/controller/VaultController.java | 32 +-- v2/src/main/java/com/skyflow/Skyflow.java | 2 +- v2/src/main/java/com/skyflow/VaultClient.java | 5 + 16 files changed, 270 insertions(+), 33 deletions(-) create mode 100644 flowvault/dependency-reduced-pom.xml diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java index 7475012d..a60dc02b 100644 --- a/common/src/main/java/com/skyflow/BaseSkyflow.java +++ b/common/src/main/java/com/skyflow/BaseSkyflow.java @@ -16,7 +16,7 @@ import java.util.Map; -abstract class BaseSkyflow implements ISkyflow { +abstract class BaseSkyflow, V extends BaseVaultConfig> implements ISkyflow { protected final BaseSkyflowClientBuilder builder; protected BaseSkyflow(BaseSkyflowClientBuilder builder) { @@ -124,8 +124,8 @@ protected final void addVaultConfigTemplate(V vaultConfig) throws SkyflowExcepti throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdAlreadyInConfigList.getMessage()); } - this.vaultConfigMap.put(vaultId, vaultConfigCopy); onVaultConfigAdded(vaultConfigCopy); + this.vaultConfigMap.put(vaultId, vaultConfigCopy); } protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowException { @@ -139,8 +139,9 @@ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowExce throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage()); } V previousConfig = this.vaultConfigMap.get(vaultId); - V merged = mergeVaultConfig(vaultConfig, previousConfig); + V merged = mergeVaultConfig(vaultConfig, cloneVaultConfig(previousConfig)); onVaultConfigUpdated(merged); + this.vaultConfigMap.put(vaultId, merged); } protected final void removeVaultConfigTemplate(String vaultId) throws SkyflowException { @@ -158,10 +159,10 @@ protected final void addSkyflowCredentialsTemplate(Credentials credentials) thro try { credentialsCopy = (Credentials) credentials.clone(); } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); + throw new SkyflowException(e.getMessage(), e); } - this.skyflowCredentials = credentialsCopy; onCredentialsUpdated(credentialsCopy); + this.skyflowCredentials = credentialsCopy; } protected abstract void validateVaultConfig(V vaultConfig) throws SkyflowException; @@ -169,11 +170,11 @@ protected final void addSkyflowCredentialsTemplate(Credentials credentials) thro protected abstract boolean hasVaultClient(String vaultId); @SuppressWarnings("unchecked") - protected final V cloneVaultConfig(V vaultConfig) { + protected final V cloneVaultConfig(V vaultConfig) throws SkyflowException { try { return (V) vaultConfig.clone(); } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); + throw new SkyflowException(e.getMessage(), e); } } @@ -181,7 +182,7 @@ protected final String extractVaultId(V vaultConfig) { return vaultConfig.getVaultId(); } - protected final V mergeVaultConfig(V incoming, V existing) { + protected final V mergeVaultConfig(V incoming, V existing) throws SkyflowException { if (incoming.getEnv() != null) { existing.setEnv(incoming.getEnv()); } @@ -192,7 +193,7 @@ protected final V mergeVaultConfig(V incoming, V existing) { try { existing.setCredentials((Credentials) incoming.getCredentials().clone()); } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); + throw new SkyflowException(e.getMessage(), e); } } return existing; diff --git a/common/src/main/java/com/skyflow/BaseVaultClient.java b/common/src/main/java/com/skyflow/BaseVaultClient.java index fa648611..3d5b0d32 100644 --- a/common/src/main/java/com/skyflow/BaseVaultClient.java +++ b/common/src/main/java/com/skyflow/BaseVaultClient.java @@ -55,7 +55,7 @@ protected OkHttpClient buildSharedHttpClient(Supplier tokenSupplier) { .build(); } - protected void prioritiseCredentials(BaseCredentials vaultSpecificCredentials) throws SkyflowException { + protected synchronized void prioritiseCredentials(BaseCredentials vaultSpecificCredentials) throws SkyflowException { try { BaseCredentials original = this.finalCredentials; if (vaultSpecificCredentials != null) { @@ -88,7 +88,7 @@ protected void prioritiseCredentials(BaseCredentials vaultSpecificCredentials) t } } - protected void setBearerToken(BaseCredentials vaultSpecificCredentials) throws SkyflowException { + protected synchronized void setBearerToken(BaseCredentials vaultSpecificCredentials) throws SkyflowException { prioritiseCredentials(vaultSpecificCredentials); BaseValidations.validateCredentials(this.finalCredentials); if (this.finalCredentials.getApiKey() != null) { diff --git a/common/src/main/java/com/skyflow/ISkyflow.java b/common/src/main/java/com/skyflow/ISkyflow.java index ac5fd747..1c29b780 100644 --- a/common/src/main/java/com/skyflow/ISkyflow.java +++ b/common/src/main/java/com/skyflow/ISkyflow.java @@ -5,7 +5,7 @@ import com.skyflow.enums.LogLevel; import com.skyflow.errors.SkyflowException; -public interface ISkyflow { +public interface ISkyflow, V extends BaseVaultConfig, C extends BaseCredentials> { Self addVaultConfig(V vaultConfig) throws SkyflowException; Self updateVaultConfig(V vaultConfig) throws SkyflowException; diff --git a/common/src/main/java/com/skyflow/config/BaseCredentials.java b/common/src/main/java/com/skyflow/config/BaseCredentials.java index 34b2c117..48ab70dc 100644 --- a/common/src/main/java/com/skyflow/config/BaseCredentials.java +++ b/common/src/main/java/com/skyflow/config/BaseCredentials.java @@ -1,6 +1,7 @@ package com.skyflow.config; import java.util.ArrayList; +import java.util.HashMap; import java.util.Map; public class BaseCredentials implements Cloneable { @@ -69,7 +70,15 @@ public void setContext(Map context) { } @Override + @SuppressWarnings("unchecked") public Object clone() throws CloneNotSupportedException { - return super.clone(); + BaseCredentials copy = (BaseCredentials) super.clone(); + if (this.roles != null) { + copy.roles = new ArrayList<>(this.roles); + } + if (this.context instanceof Map) { + copy.context = new HashMap<>((Map) this.context); + } + return copy; } } diff --git a/common/src/main/java/com/skyflow/errors/ErrorMessage.java b/common/src/main/java/com/skyflow/errors/ErrorMessage.java index e3b5924b..1e4d9178 100644 --- a/common/src/main/java/com/skyflow/errors/ErrorMessage.java +++ b/common/src/main/java/com/skyflow/errors/ErrorMessage.java @@ -63,6 +63,7 @@ public enum ErrorMessage { BearerTokenExpired("%s0 Validation error. Bearer token is invalid or expired. Please provide a valid bearer token."), // Insert + InsertRequestNull("%s0 Validation error. InsertRequest object is null. Specify a valid InsertRequest object."), TableKeyError("%s0 Validation error. 'table' key is missing from the payload. Specify a 'table' key."), EmptyTable("%s0 Validation error. 'table' can't be empty. Specify a table."), ValuesKeyError("%s0 Validation error. 'values' key is missing from the payload. Specify a 'values' key."), diff --git a/common/src/main/java/com/skyflow/errors/SkyflowException.java b/common/src/main/java/com/skyflow/errors/SkyflowException.java index 138fcc68..676bdd74 100644 --- a/common/src/main/java/com/skyflow/errors/SkyflowException.java +++ b/common/src/main/java/com/skyflow/errors/SkyflowException.java @@ -90,7 +90,7 @@ private void setHttpStatus() { } public int getHttpCode() { - return httpCode; + return httpCode == null ? 0 : httpCode; } public JsonArray getDetails() { diff --git a/common/src/main/java/com/skyflow/logs/ErrorLogs.java b/common/src/main/java/com/skyflow/logs/ErrorLogs.java index b77eee2c..bbb96fce 100644 --- a/common/src/main/java/com/skyflow/logs/ErrorLogs.java +++ b/common/src/main/java/com/skyflow/logs/ErrorLogs.java @@ -54,6 +54,7 @@ public enum ErrorLogs { EMPTY_TABLE_NAME("Invalid %s1 request. Table name can not be empty."), VALUES_IS_REQUIRED("Invalid %s1 request. Values are required."), EMPTY_VALUES("Invalid %s1 request. Values can not be empty."), + INSERT_REQUEST_NULL("Invalid %s1 request. Insert request can not be null."), RECORDS_IS_REQUIRED("Invalid %s1 request. Records are required."), EMPTY_RECORDS("Invalid %s1 request. Records can not be empty."), INVALID_RECORD("Invalid %s1 request. Invalid record. Specify a valid record."), diff --git a/common/src/main/java/com/skyflow/utils/BaseUtils.java b/common/src/main/java/com/skyflow/utils/BaseUtils.java index c4a7b6f3..e536c111 100644 --- a/common/src/main/java/com/skyflow/utils/BaseUtils.java +++ b/common/src/main/java/com/skyflow/utils/BaseUtils.java @@ -81,9 +81,14 @@ public static PrivateKey getPrivateKeyFromPem(String pemKey) throws SkyflowExcep if (pemKey.contains(PKCS8PrivateHeader)) { privateKeyContent = privateKeyContent.replace(PKCS8PrivateHeader, ""); privateKeyContent = privateKeyContent.replace(PKCS8PrivateFooter, ""); - privateKeyContent = privateKeyContent.replace("\n", ""); privateKeyContent = privateKeyContent.replace("\r\n", ""); - privateKey = parsePkcs8PrivateKey(Base64.getDecoder().decode(privateKeyContent)); + privateKeyContent = privateKeyContent.replace("\n", ""); + try { + privateKey = parsePkcs8PrivateKey(Base64.getDecoder().decode(privateKeyContent)); + } catch (IllegalArgumentException e) { + LogUtil.printErrorLog(ErrorLogs.INVALID_KEY_SPEC.getLog()); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidKeySpec.getMessage()); + } } else { LogUtil.printErrorLog(ErrorLogs.JWT_INVALID_FORMAT.getLog()); throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.JwtInvalidFormat.getMessage()); diff --git a/common/src/test/java/com/skyflow/BaseSkyflowTests.java b/common/src/test/java/com/skyflow/BaseSkyflowTests.java index 12ae256c..2e18a1ea 100644 --- a/common/src/test/java/com/skyflow/BaseSkyflowTests.java +++ b/common/src/test/java/com/skyflow/BaseSkyflowTests.java @@ -250,7 +250,7 @@ public Env getEnv() { } @Test - public void testMergeVaultConfigWithNullClusterIdFallsBackToPreviousClusterId() { + public void testMergeVaultConfigWithNullClusterIdFallsBackToPreviousClusterId() throws SkyflowException { BaseVaultConfig existing = newConfig(vaultID, clusterID, Env.DEV); BaseVaultConfig incoming = new BaseVaultConfig(); incoming.setVaultId(vaultID); diff --git a/flowvault/dependency-reduced-pom.xml b/flowvault/dependency-reduced-pom.xml new file mode 100644 index 00000000..92fc11f2 --- /dev/null +++ b/flowvault/dependency-reduced-pom.xml @@ -0,0 +1,195 @@ + + + + skyflow + com.skyflow + 1.0.0 + + 4.0.0 + skyflow-flowvault-java + ${project.groupId}:${project.artifactId} + 1.0.0 + Skyflow V3 SDK for the Java programming language + https://github.com/skyflowapi/skyflow-java/tree/main + + + skyflow + skyflow + + + + + The MIT License (MIT) + https://github.com/skyflowapi/skyflow-java/blob/main/LICENSE + + + + + + true + src/main/resources + + + + + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + com.skyflow:common + + + + + + + + + + + jfrog + + + central + prekarilabs.jfrog.io-releases + https://prekarilabs.jfrog.io/artifactory/skyflow-java + + + snapshots + prekarilabs.jfrog.io-snapshots + https://prekarilabs.jfrog.io/artifactory/skyflow-java + + + + + maven-central + + + + org.sonatype.central + central-publishing-maven-plugin + 0.4.0 + true + + central + true + true + + + + + + + central + https://central.sonatype.com/api/v1/publisher/upload + + + central-snapshots + https://central.sonatype.com/api/v1/publisher/upload + + + + + + + com.fasterxml.jackson.core + jackson-databind + 2.17.2 + compile + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + 2.18.6 + compile + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.18.6 + compile + + + io.github.cdimascio + dotenv-java + 2.2.0 + compile + + + com.google.code.gson + gson + 2.10.1 + compile + + + com.squareup.okhttp3 + okhttp + 4.12.0 + compile + + + io.jsonwebtoken + jjwt + 0.12.6 + compile + + + junit + junit + 4.13.2 + test + + + hamcrest-core + org.hamcrest + + + + + org.powermock + powermock-module-junit4 + 2.0.9 + test + + + powermock-module-junit4-common + org.powermock + + + hamcrest-core + org.hamcrest + + + + + org.powermock + powermock-api-mockito2 + 2.0.9 + test + + + powermock-api-support + org.powermock + + + mockito-core + org.mockito + + + + + + UTF-8 + 8 + false + 8 + ${project.version} + + diff --git a/flowvault/src/main/java/com/skyflow/VaultClient.java b/flowvault/src/main/java/com/skyflow/VaultClient.java index c8843f3e..9f326349 100644 --- a/flowvault/src/main/java/com/skyflow/VaultClient.java +++ b/flowvault/src/main/java/com/skyflow/VaultClient.java @@ -28,7 +28,7 @@ protected void setCommonCredentials(Credentials commonCredentials) throws Skyflo super.prioritiseCredentials(this.vaultConfig.getCredentials()); } - protected void setBearerToken() throws SkyflowException { + protected synchronized void setBearerToken() throws SkyflowException { super.setBearerToken(this.vaultConfig.getCredentials()); if (apiClient == null) { updateExecutorInHTTP(); diff --git a/flowvault/src/main/java/com/skyflow/utils/Utils.java b/flowvault/src/main/java/com/skyflow/utils/Utils.java index db2d00bd..5880344b 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Utils.java +++ b/flowvault/src/main/java/com/skyflow/utils/Utils.java @@ -738,11 +738,11 @@ public static BulkInsertResponse formatBulkInsertResponse(V1InsertResponse respo BulkInsertResponse formattedResponse = null; List successRecords = new ArrayList<>(); List errorRecords = new ArrayList<>(); - if (response != null) { + if (response != null && response.getRecords().isPresent()) { String requestId = extractRequestId(headers); List record = response.getRecords().get(); int indexNumber = batch * batchSize; - int recordsSize = response.getRecords().get().size(); + int recordsSize = record.size(); for (int index = 0; index < recordsSize; index++) { if (record.get(index).getError().isPresent()) { ErrorRecord errorRecord = new ErrorRecord(indexNumber, record.get(index).getError().get(), record.get(index).getHttpCode().orElse(500), requestId); diff --git a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java index c835cc78..1d0228ed 100644 --- a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java @@ -152,6 +152,12 @@ public static void validateVaultConfiguration(VaultConfig vaultConfig) throws Sk public static void validateInsertRequest(InsertRequest insertRequest) throws SkyflowException { + if (insertRequest == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INSERT_REQUEST_NULL.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InsertRequestNull.getMessage()); + } String table = insertRequest.getTable(); ArrayList records = insertRequest.getRecords(); if (records == null) { @@ -384,6 +390,12 @@ public static void validateTokenizeRequest(TokenizeRequest request) throws Skyfl // ── Bulk (batched/concurrent) request validations ──────────────────────── public static void validateBulkInsertRequest(BulkInsertRequest insertRequest) throws SkyflowException { + if (insertRequest == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INSERT_REQUEST_NULL.getLog(), InterfaceName.INSERT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InsertRequestNull.getMessage()); + } String table = insertRequest.getTable(); ArrayList records = insertRequest.getRecords(); if (records == null) { diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java index bf6abc42..476ce9d5 100644 --- a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -884,25 +884,33 @@ private BulkInsertResponse processBulkInsertSync( ArrayList originalPayload, RequestInterceptor interceptor, BatchConfig cfg - ) throws ExecutionException, InterruptedException { + ) throws ExecutionException, InterruptedException, SkyflowException { LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); List successRecords = new ArrayList<>(); List errorRecords = Collections.synchronizedList(new ArrayList<>()); List> futures = this.insertBatchFutures(insertRequest, errorRecords, interceptor, cfg); - CompletableFuture allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); - allFutures.join(); - - for (CompletableFuture future : futures) { - BulkInsertResponse futureResponse = future.get(); - if (futureResponse != null) { - if (futureResponse.getSuccess() != null) { - successRecords.addAll(futureResponse.getSuccess()); - } - if (futureResponse.getErrors() != null) { - errorRecords.addAll(futureResponse.getErrors()); + try { + CompletableFuture allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + try { + allFutures.join(); + } catch (Exception e) { + // individual batch errors are already captured + } + for (CompletableFuture future : futures) { + BulkInsertResponse futureResponse = future.get(); + if (futureResponse != null) { + if (futureResponse.getSuccess() != null) { + successRecords.addAll(futureResponse.getSuccess()); + } + if (futureResponse.getErrors() != null) { + errorRecords.addAll(futureResponse.getErrors()); + } } } + } catch (Exception e) { + LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); } BulkInsertResponse response = new BulkInsertResponse(successRecords, errorRecords, originalPayload); LogUtil.printInfoLog(InfoLogs.INSERT_REQUEST_RESOLVED.getLog()); diff --git a/v2/src/main/java/com/skyflow/Skyflow.java b/v2/src/main/java/com/skyflow/Skyflow.java index 2daf9b27..66640f0e 100644 --- a/v2/src/main/java/com/skyflow/Skyflow.java +++ b/v2/src/main/java/com/skyflow/Skyflow.java @@ -106,7 +106,7 @@ protected void onVaultConfigAdded(VaultConfig vaultConfig) throws SkyflowExcepti @Override protected void onVaultConfigUpdated(VaultConfig updatedConfig) throws SkyflowException { - this.vaultClientsMap.get(updatedConfig.getVaultId()).updateVaultConfig(); + this.vaultClientsMap.get(updatedConfig.getVaultId()).updateVaultConfig(updatedConfig); } @Override diff --git a/v2/src/main/java/com/skyflow/VaultClient.java b/v2/src/main/java/com/skyflow/VaultClient.java index a24ef8d2..84289e8f 100644 --- a/v2/src/main/java/com/skyflow/VaultClient.java +++ b/v2/src/main/java/com/skyflow/VaultClient.java @@ -85,6 +85,11 @@ protected void updateVaultConfig() throws SkyflowException { super.prioritiseCredentials(this.vaultConfig.getCredentials()); } + protected void updateVaultConfig(VaultConfig newConfig) throws SkyflowException { + this.vaultConfig = newConfig; + updateVaultConfig(); + } + protected V1DetokenizePayload getDetokenizePayload(DetokenizeRequest request) { List recordRequests = new ArrayList<>(); From 7caa863ed770473344eef5d7090eb18a300f9995 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow <156889717+saileshwar-skyflow@users.noreply.github.com> Date: Fri, 24 Jul 2026 21:23:36 +0530 Subject: [PATCH 27/28] SK-2984 Add contract testing for v2 SDK (#352) --- .cspell.json | 1 + .github/workflows/contract-tests.yml | 118 ++++++++++++++++++++++++ scripts/contract-snapshot-update.sh | 27 ++++++ v2/api-report/skyflow-java.baseline.jar | Bin 0 -> 963999 bytes v2/pom.xml | 78 ++++++++++++++++ 5 files changed, 224 insertions(+) create mode 100644 .github/workflows/contract-tests.yml create mode 100755 scripts/contract-snapshot-update.sh create mode 100644 v2/api-report/skyflow-java.baseline.jar diff --git a/.cspell.json b/.cspell.json index 757f0c48..bb8aef81 100644 --- a/.cspell.json +++ b/.cspell.json @@ -6,6 +6,7 @@ "**/*.{java,md,xml,yml,yaml,json,txt,properties}" ], "words": [ + "japicmp", "Skyflow", "skyflow", "skyflowapi", diff --git a/.github/workflows/contract-tests.yml b/.github/workflows/contract-tests.yml new file mode 100644 index 00000000..f50424b6 --- /dev/null +++ b/.github/workflows/contract-tests.yml @@ -0,0 +1,118 @@ +name: Contract Tests + +on: + pull_request: + branches: + - main + - release/* + +jobs: + contract-tests: + name: Contract Tests + runs-on: ubuntu-latest + + permissions: + contents: read + pull-requests: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '11' + cache: 'maven' + + - name: Verify API surface snapshot + run: mvn -B install -pl common,v2 -am -DskipTests -Dmaven.javadoc.skip=true -Dgpg.skip=true + + - name: Show API surface diff + if: failure() + run: | + echo "### API surface changes detected ###" + echo "See v2/target/japicmp/default-cli.diff for the full comparison against v2/api-report/skyflow-java.baseline.jar." + echo "If this change is intentional, run scripts/contract-snapshot-update.sh and commit the updated baseline jar." + echo "" + cat v2/target/japicmp/default-cli.diff || true + + - name: Upload API surface diff on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: api-surface-diff + path: v2/target/japicmp/** + retention-days: 7 + + # The step above only shows a diff when the CURRENT build differs from the + # committed baseline - once someone runs contract-snapshot-update.sh and + # commits the refreshed baseline jar, that check goes green and shows nothing. + # A reviewer looking at a green PR that touches api-report/skyflow-java.baseline.jar + # (a binary file) would otherwise have no way to see WHAT was just approved as + # the new contract. These steps explicitly diff the OLD committed baseline + # (from the PR's base branch) against the NEW committed baseline (from this PR) + # and post it as a PR comment, regardless of whether the check above passed. + - name: Check if contract baseline was updated in this PR + id: baseline-diff-check + if: always() && github.event.pull_request + run: | + git fetch origin "${{ github.event.pull_request.base.ref }}" --depth=1 + if git diff --name-only "origin/${{ github.event.pull_request.base.ref }}" HEAD -- v2/api-report/skyflow-java.baseline.jar | grep -q .; then + echo "changed=true" >> "$GITHUB_OUTPUT" + else + echo "changed=false" >> "$GITHUB_OUTPUT" + fi + + - name: Diff old vs new contract baseline + if: always() && steps.baseline-diff-check.outputs.changed == 'true' + run: | + curl -sL -o /tmp/japicmp-cli.jar "https://repo.maven.apache.org/maven2/com/github/siom79/japicmp/japicmp/0.26.0/japicmp-0.26.0-jar-with-dependencies.jar" + mvn -q -B dependency:build-classpath -pl v2 -Dmdep.outputFile=/tmp/v2-classpath.txt -Dmaven.javadoc.skip=true -Dgpg.skip=true + git show "origin/${{ github.event.pull_request.base.ref }}:v2/api-report/skyflow-java.baseline.jar" > /tmp/old-baseline.jar + + java -jar /tmp/japicmp-cli.jar \ + -o /tmp/old-baseline.jar \ + -n v2/api-report/skyflow-java.baseline.jar \ + -a protected \ + -e "com.skyflow.generated.*;com.skyflow.utils.*" \ + --old-classpath "$(cat /tmp/v2-classpath.txt)" \ + --new-classpath "$(cat /tmp/v2-classpath.txt)" \ + -m \ + --markdown > /tmp/contract-baseline-diff.md || true + + cat /tmp/contract-baseline-diff.md + + - name: Comment contract baseline change on PR + if: always() && steps.baseline-diff-check.outputs.changed == 'true' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const summary = fs.readFileSync('/tmp/contract-baseline-diff.md', 'utf8'); + const marker = ''; + const body = `${marker}\n## Contract baseline change detected\n\nThis PR updates \`v2/api-report/skyflow-java.baseline.jar\` (the approved public API contract). Here is exactly what it changes, comparing the baseline on \`${{ github.event.pull_request.base.ref }}\` against the baseline committed in this PR:\n\n${summary}`; + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + const existing = comments.find(c => c.body && c.body.includes(marker)); + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body, + }); + } diff --git a/scripts/contract-snapshot-update.sh b/scripts/contract-snapshot-update.sh new file mode 100755 index 00000000..95201b9a --- /dev/null +++ b/scripts/contract-snapshot-update.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Regenerates the v2 contract-testing baseline (api-report/skyflow-java.baseline.jar) +# from the CURRENT working tree and overwrites the committed snapshot. +# +# Run this after an intentional public API change to v2, review the resulting +# git diff on the jar (a new binary blob) alongside your code change, and commit +# both together. This is the only way the committed baseline should ever change - +# japicmp never pulls a published version for this comparison. +set -euo pipefail + +cd "$(dirname "$0")/.." + +mvn -B package -pl common,v2 -am -DskipTests -Dmaven.javadoc.skip=true -Dgpg.skip=true + +SHADED_JAR=$(ls v2/target/skyflow-java-*-with-common.jar | head -n1) + +if [ -z "$SHADED_JAR" ]; then + echo "Error: could not find a built v2/target/skyflow-java-*-with-common.jar. Did the build succeed?" + exit 1 +fi + +mkdir -p v2/api-report +cp "$SHADED_JAR" v2/api-report/skyflow-java.baseline.jar + +echo "--------------------------" +echo "Updated v2/api-report/skyflow-java.baseline.jar from $SHADED_JAR" +echo "Review the diff and commit this file alongside your API change." diff --git a/v2/api-report/skyflow-java.baseline.jar b/v2/api-report/skyflow-java.baseline.jar new file mode 100644 index 0000000000000000000000000000000000000000..c35c4ef716e4ddc0ad160475998ad8ef9edd5461 GIT binary patch literal 963999 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

qJBDHy^k~ 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˽uXMJE3)Iz#YUi1s3W( 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≻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≪KJ-!-ksM!PfKqO-e-QKw`@9cOj-i#Qr zgT%bppg~vaV=K4Hg03h_ww&=r5XqfRdb`|l&$|?ndd8P>6jXRcNxKfLYd~%B8Y+H9 zMm>^~WshX7Ddom?tX3TO-)dA6eCPG08RY#`F3y8uS&h4YCm`y@RR73H7h{YdO{^Q< zEfNESzZ~P-DR9A!;?-wm-Cr2KF+|w#e4g2KcpPQa6MCpyY>z&4C&Aoym=f=ZYydwn zpspVpieyelmnB&O>{1rFk7O}5(ps=VCv`MouRpsYi9JYr1-^%=rE5VZr7Qjr)GwWp zZsz15myM-vXNcxyI5mXwL#hR*yLLHKVtVST@2nMX z91D&#pdFl<-_M2YOqb2fMoTMz*XGrgkAXSME}huw@FOU*o;DB3O#U>!(L61|})%IQZ7$bo0%{iT$s}bxmg6=V6p2xTqHR-< zA*Tsdf7)@##QbF)g#8c;B29B?k2@xQfZTXY@;#F6HqEkL0NHA4Nb6km85k(mxx1*v zT4L$M9Ia0bDH-cLtk+yq!K%ZBQ*bcl8o!+^pwvRv1CyHD;w5^V7$D1V#9(+By)J}~ z%sHacsUO^hcVTIZdXsHOHu+^D{50}vmMq1TSJAlr!A-sc^>zY6UXCf7*eF)t)gvTq zSD0GSDN3y!``uOwQq450+cL$uJ;(5I!g1Z@M^@Q7GWQXl>Bo24CcjEVdXAp;mxU1Q zj)>UH`2po}vz@-S-EKGW0arV3T)qa| zKc8o)v{kYB7|E3O-Wy0xjWom*g?k!OPN%$2vFdM!p&nH{u+cFCFu6wOJ|sJASzg34%Y+Am zFSNf#9>r*+al(o3a$`i4?d=spwm{vib?vG53 zBvk^qNF^-Z2Ft+Zj~%X5JlWL3hdH9c^9{j~4WyO9ZsNZ+am5X3M>(tomiY)3N4p0Lk7}Syy<@hsECpx*e^E zv+BzGM9Is<<8WEq5E6~s!mfP5^aqK5ukH%W)nfIy-d3t!%O%c|W22c1>H^szSyfvz_H_7W7utTA59L6TX5-1L`Z&HxVZ4!qboRmiL)w+k<$cu1&FQ$qYKht zs8}2Egd@YyzXo3-AJ#>fH9ow`ra#nK9-Pr<^6KV^=`0f?*n|Qz4$AikSaF?`b6^}+ zFng2hrlZ7D37c3eAym;`iH&l_c5(8G@K(FxroSriD+aBc5lJ|!aMXT&$D3UVx$GX6 z$3;@lnK|t)ZF6mP=*N=O+hT#z|{49)DA(<0WD30tm;9k%H8?zM7<9ZyP0#^7b~aQG_fFtx@Hg?xwjrFrwf z`*N*rAy1y$?YU~Ylfs|Ikd}{2RRY?5-#J;S*Jq}yP>Om`g5b;ua9J}12Mzl$-I**o zKoiP#Oq_wQh)r4PsNk=LKD_Z1FE$4b`Mc|2{iX~QC+v2oeh(a3s{lFaoNXf=e*Qxo zkx82!C;T-{75%qq>R)^Gel-NOV>v`>C&~U<`G!)51*%88SFb?i9(<0*|EH z=2dPVFAKadTCD8DyUDHUNr_2V{u=MY?}XP6@!V(F;Pe9Sq==c46-uA&UfdZOnMm-; ze)I5MKib^S_WSgO+GfL}#^}*O>w8w}QK$G;nmVwQiar|{X@@eL+p9Z616?@_zTOuf z`34kqc3|S?d@ihG62Eq;Ij>V1xME$rHkZ!WAW$ijqYt?z?xHcDq8pPbT zUgFd&T5sHHC6+K~>-L1=_2c9M>it_9plhXJ++Wv2Rw<`uZ;chP#1~dVAsZeR5Kbn_ zI2Ai8&u1i&lEH-@kjke2^i;lHiJ=-10kF3Wc^I~ry}@%S>d;NlNkI3RBeKJsM_oI# z9bwX>DuXEoEeyTCoyn4I$bF_*e?(|UQEEI#7g(mCRHdqS#{ycqRO#JBR$i#N;L zXcrO;8R4d=wnvS@qI2KSVOQ#M*{HPtpr)z{HwA?Ucvl-C z147dNc%wWvV_ddtdSZxijck_i9k6m`i+jPljS_9yd8$Ks3s|F>*6vzH-jkZ{2m%T~*B@L7j9_cocqx`Z|A5mxXfhs-`Ry{Ye#D@-O zBH+Vdf6ENke7%gB-s%M+Q4A%K%!BB;RwIa+lLbiJmXx%*ezx8FvOe+&`XR~8GdC`k z4he;m7>IF$%qABrgxEr`BRB0E5EGb}Oc5shTW~-Z@lO=&AIQJNHE}hd zOBY|ye*S-}Kj-=nNE(r^{8kkU8-NJF3E*g9X#M4)`lkx7L)}UpSscR`0>rA92pv_h zvJe_eL|3#Ou^}Wqge-?_I?v{$F0H%Ql>O2c<@m$5>xuoIdDdxqbEokhg@9-q|myE{aC~ZXllkWwz+v6RjTTtgFA5k6D9dYUXSU^L87x+GJD#jNU ztOkGS<99%)21eqw67R`o1!Ug@P^}##f_NVE5d%^;g&tbAdeE$f|M_N|J-ffpZ=xMl zsA{N1R7OADUJhY^^=~_p)v0OBg^GrFCES#?dJEw+wMNV#rlf+?GUV1Ym02|=D|^za zVrGaKj|7Ahx3i*4JpcuKQxwy)XC;YQN!TeF{%8^T?@R@9*xh+?T3J>xRc-V;p1C8r zlka`tQ;p2bDNGfRqa^Gtm90Fb%j*uP6Ll@K;&(w=hd%2&COy+fEwYmz3F{N0LSlh7 z++#UZnhc{1`0L%_=tBgG?5gSe!s(pUL1kZ=j*nVJV`du)+Rj=X)l_t(`LM-G-`!H2 z@)cZLcrt6P7Yxj4=SmD zP4$q4qEX8B=x7J#Bby(PHe+*`z+TN*vk;4Lp^#x8Kb3uiS;>=j!Yry<2%)f0JGGf_ zea>Uf5{gbuZ7f5UO>IR)26$IGZZ7o-iNJQ%78jrW>9CqCI*Ryc?*TZ2cTC@RIH4pl zaVRkpIEam*TZ1exnHfk50I4-5Cie1yw0!~8#1U_>6Qo*4YRPL(u#LRQ2V7N^rbg?T zb@6htqkc_r{oN~le6 z8FAHFp*YGaRs05Li*_?=NJgd+aA+W!+HqP|v<)_EWwO>x>v-aiNh^;%%R!bZ=flhG z?Q#32D8%9m9UdeMX#p!13%VBBz;>tMT596EeS1DTBA@O=Nck|eq^&K<6ehWr4oi!o z8;=kX4rD`c;Mbg;2ETFEk!q?zRaBC_cCWuLtNqG@X-Z<+$92lx)rIGEw#Fa}6czI- zR^gr;$tk^=-k6Y0x>s|?$6e`F?XtY#uW=Zu0?OZ(rVYe^{&AiMnz$knBif z>hH82bUcDgPrQNANU6xmlc=^T%_o+%BrmU)IUADgK(4-*047YB!SoOl>^ER^Sq8QS zpbjn$=!&t+(pY}a#Vf;B@@ivKk{vR6n?-P@6uPV}Ry~%5ATH@D7T`k-G$+FM?aVrw z7m>dSdfqVOAjE*=Q5}ohf$g#&7fug@J@pgU{1i#t0e@BV92djMtz+@!^+EV+Rc#?Yw-Qw>;4;f!bQ{Zzoe%qQVA#UAeq(Ud;9jpo#eGWq` zdB#;WK9C=#-ZkzdFDY_>YHRbB?Hnq3L2U#)BeNPQiHA#<=p)?Y?R2g?`9%tW$;Gz0 zGC9WI^2xqX-TR%ewA!OBo#-p!Wa?RFk}QZeniG3uf1}SX$XS(4@tCKar6C>x)8rJ^ zn?!PBAI;kJ4~j1SO)}F}ET;$&&##YN)Ih&K$0t2|z#>JyDo+7r)H!mU2iwi9x#d!t?z^jkq698&i;TqQXbRKnF3HPHmo);4g zp0T#}uvrMD?jW?n6f=Y|iu9vfgLD60rAuJ@y%m510hxdQcZB_a^2C(1wRds;o3a1r zYx6H9?msozD!P9elQt5-LV^U1P-qL)3e4{WQ=8PRuxCK1Ajk!w01qw_bUVHKa$GIM z2axyj_wdit3yr5*jfFl6*>CxlQ<+~eGg-eX)?3`NogO*evYB6wwz~8|e+O$pTX-k; zv+!kiqf@T;r*PSp-d&&!UN0=S9VhhSdh>>XbSlb`;<_no^zh<7xpKTg@7~ zO7}&&nDaNwUj91Z(;=#Er6xgkJSv!A(WzO_2c=wNpMbWq*ACcc_DzAIyRx7#5nmQZ zI&x(tS=@kdkki(wDcf2#-i+=zLWr+jZ@oBQ#Zy1}CNm7WIb%Om)<#?JTo5VRVK!zK+}zvE!8yrV;i~ikWH>+e85IuV$%q4li|h@$JfZ)Hb8Qx7HnTg+d@sz zmv`VPdlx&xJ9U_6yy}y$`G6~)By7#RvM#}RxH-in!iPFy!8nr$iM6}3PL|7Ru@pn) z%H3*px)bBF_+7}k!g4x>mu@Axd?#KhwL$0Z=_zdpi^Pi2K&A<4Qt-Pr&_LG zIkyE3$AW0lx#G-S08{uFQT^mdO!{{PmW2TXJe*Fqs1zH6;2kyfUEuu8&2TpaUV@9r z7F>q-pa5n%R~E)_50iqRs;IRE$5xbv+xmB9rDJ!?ZOkUt^*??##Z0ZTSYloSHV+L& zAd{iu^xghO8yrJuvQ9_cPBDGHis)`_2XFD*hl`tp<Ab!V@X1}J0bx>fvZjCxwR9~zB3_QRfa?ug{rDjT-+wgKirK)T!^jG zPRd3tGI$NS58a&Y;KXzrFVm*doaF)?c;}R{)OGUx%2__r2VxbG1=}LAC_Tvp_J4~c zk2%*N7Sr2vev&tM@1PpJ6w17#gf(M$1>d9q4?qgK2QFGQ&=G{mhZ-Q(2aSLAPXs4{ z8fA+HgJPtiYs8BL#=t7D@AF39H~{vO0-d4TF5*XR`XzTDI>>jiV}u+1s0wwEJdZMR zk}@K+=Lw{lXZ&eDv0EZCJp(4L&wFajJ<$C^;MmBN~PbTZ>--xHKUZJEs7b(n(k59ON)={yD9->c;Yz{m}@2wGy$=_d6O z1<)QE!*fnyRdXp#%Lz@P@^Ns>(Dz11C#6(Ha-I3pzoRX1!87w%aYc=fp~nIm4*mXm z6gHGkUT1$j3U~kQ65>A*;{R_yw5Yo=;2+AGzl%UpT#psofZ3Ti}LXMvPLgd zYDSq4rcDMWeX2haGc>ik<)}P#P`(;I7i-R6x+-nQr_95;q?)BzU3dl>Jmv6p;OHxt z!5YDy7;lJ1Vq4nun~J)Ij=~|ySvo;s!)>BKQ>EDI5qqyz6^%A$qm73K=uilBK>cTo z@V0^P%ZCIO;!SWLzv&5V1J)Y(fadnM+2^tI6c8g_LuW=SqpaSA(nT_X&GXp0DcBHi262=MU4n< zNw*v9zkW95Z&IU*UqX5J|0b0GSBl_&u(AJx#{U zYSr6=5Y{3d(pQy(R)*|ldHdmmp@;B|94A?UC;^-uJ^m3u^B0iq97#mozbqzSPXDh_N666F z%FfjEZ)jJloXH_8BK-MITalO~P5Ui;w{W+KKwI&8Rx1~!MuFsOIn57$0gTq%mi}du z2F2LJ&+dhs2CKRG3BN6jc|=1%@C>>~=H+VYO1Cxs!o=_E`}W-ctbW2=)DO(&cR7hL zZrHbY40Ei$Kgc}B*X#aJRO-TUopdzi=n z-Z{9ke%k_#ZQHh;bjP-x9ouF{JGR-eZ5tii>ex<)o%G9hzI$%nbE@ur=hds)wQBvf z|5*aWn{6K{&nOKJH`cvC0YqVbNAnJH3n2hi=cS(-2zB`-{L_UO5^3&dN8F3qlV zWxlWgF?C+K+Yj4g9gBu937ET`G&OM_f<(osZ4Ig`G^l3~Y5e)X~KW(m$;jE{?=)rgj^Sk_0@>fs;M*I+%bX zn~>zH)2i{#lVzBlQ-Ex zxPqfLy;7W+t)d+Xq3=J~i>BdYphjgWm8(atOI1c|E)TxNb*YTooDoa;{$|5&Q+205 z9mFMQWVMWxz>p%~f{Pf~5fc1R$9*uZ*^y@|*av(6G3fW+@dC74hE zIWM70E(SsB9>17Z2G-O{e+R)AF07wdK*5+mRN%nCTL+)|I}&JWiJfnH%`{*Lc5TmB z2(!QoG&iOF!(%p{AI6|B+=5f{Q>U)dSa=F*+>g-jK^;>_sp@W=!tjy=!@v5oPww!H z-o%IZWpuWP;rhJohE-LPowh3W$C6-E*G90x=`k&&CluvQTf)b8DACy_+_^Klb%{JBfNHIPfT^0otC#g1v(*&9jQO7=md$kpR za_`UDeld!Kp-;aRww_YL4Xvkqf8Jxk86Tf**|+2C+8vM7w?BuA3A-4u6Oe2;w- z9c2so{Dwb1kVEGbw{DZ3cAX}F{?1nXsI0#P5V{RjsHZty_ z;Aq`?iioO+?~FZaa7HHJwsmWo)C2EgmV!dR(aoGI!zA1TIogL9u|mH3)Lqi$OO7wg zC9_TzI_}YJ>XGBhg6qaE8Mp;u|Lkp}tW?ZhK2}qkl`Dc`*#f}3fLW7AiP=YBnH;U{ z!h~`$_bYm}h*3iz^ZDGEg*+jHem8p$0y`=uPJ!d5urX77ItnGvqwYE9CNJP2oK^Fnzk2WDUro=}5?pF-cZU z5?uPg7$SofX#tmO62?WZL)hNnSkOg3cVYD|QJJ3tpGFQ4!9@Q~yp3ItFLHVvH1GCO z*}s0Y#7fWZZe2NNu_%`D!6&UmjVh|+8h?QMNRQ9 zY_O+XS4!DtiH(A$pdN3Js5D*P~7clE-02{0b{(1m|;1^Fw;Z4Kb7*_BYaXG zZo(+v zv12_3p%cBylKrkGNDfkuWowKIj(;S=A>k%+ZZr>)13la4Dc3tz(h%B9F2|QW7nA%Y z<=HVZb1AcHZtPNKB6U2i7Bob)QW1hwnsv-pnKh5F@>duvs0J;4Om-4WTlQxBk*^Sk zn^_XX)&)ic6;i~_mR&p z80+k-2gpBjB~r;iCm()GV zMwdkSkOxJrE5$^x+IQiiF?xy%;`4ktR5di53_GP3V-eIU7 zA3IArD|IgsBdxfNY&Z*VJCYn2#i}PiU($}1J>W*Wtq`;;Sl(T`8_a{&wi<-o&pB!H z!|I0(3c@So1ln}b*o2v~`79M3FasM&bg?-tWH>&%XZZT2YOGqseZ&o+l10S4Mj69> z*lhKXQB!Yl(tx%dXy=rKkZBPeG`tll%Jd2@C&8U(P^YJiGW`SR(&ks7#i`R2+YjMm z;1=)3xH^HPmc9Gb*F=&xmCO+g#i&yvb$U;laV|@?@Ek{5lJKF%>9y zOnPeYsTxp-^f+2c`9dgh){(mSim0~S4U3{eDsaxh4_@Gpq8w~CO&}$cX5{@q#^HTQ zJhk0%8}BHgXzcq~c&DY(gXjWpXF4M@BXj!WmaVYTl%wWBV=PVQ&>-qs<(_*e6wwTu zc#8%5rn42|UF`@NB2$80=*~~4FL6mJ8L`+Qbf!x*J}Sa~U%kd5m;|bY6V)fJ<6Iqr zV6M=l&8@4I-R;+ZHjl^RrX8nBX^s{F0(aG_wFln|r)syzEnrQ2nitM@gdrBp@AiCi zpETN^kXWNj!797v&{Zwa4bUbK>Knd{I_6zr0l$C5eQes70M!}teMD6dWS!I^O;iZd z_8~-H%r2j zzG{a>MaJ^CO*r25s;2>c_)?v|<1FUV5B_{);Rfhs^in!6CW~&!^B~bKYKs=|rv%r@buC_7 z73OxZK%=v$wj`UoX>bFA6mgNbfkMa-QW zWh~ocf*D4(hoW2ngZ^dhU?`dlH%2!?F<4^pu8a1Bq1Cg_DEG6*D2xQIcO?+$7Pj5| zJFh!faK@$PlELOVHz>R1vRJ142=0#COP+nWx{G$aJNHoadaxS*aL4)E%hapcPfYEwHZ(-Q*jIO)lGs)G z>pNwN!z~#d6@%IbzJPBJD14T3+|`+-6YhQ=Br!hR(QkPPMLwCPk>(nwYhp7s59A^9 z8JHmpk{T$|$W}Z9M5O za}Uhn0!mPcu1T2}st2w!ebmQ+2n(Ca1mxQAXw{IX$RGe7h41D>!QUfV5BOgp>ha@d z1>{L~ck20*qGjzc8T(950D3dCZKtg6Azvd?wTso}Wo%$@PuUB6uT(P#@@m_Ko6zd* z3o=P7EXKYc)Q{dD-iM0_(c!Ix(=c1%-ps zuYL2#Dkc1>P}8209Ry{a#?fU;*d>X`$8PY~yV{6qEEsA~;sDh3Qnla9HS?9$C;as( z%FPXgX+SHcH2si~UQ(J%lEMNXrF&wjB3aI)7j*D#iDysJa)w^_L*-8dy0;ujR^|`So8)F8+@U; zZ?Ag)stcyoSlTV0e75{w40Qkf4E>+16a9DV@0JH8jNb8Jk{9W%h@^+*<`h0Voo8ASOt%&EyeztAPqAm8Xc zN1@5}!n;8usC;a*-0arKqf;6`N7x!VBK>M&`6WNA!zYn6L93RnnaIRBmhC1f!rWCg zyHdSjpyx*;FrHVN*M8DTH|_Wvu9GYur7J^HBb`-gmljJ^sH<}Nz){VQQoG%@(`>V- z2Q77CZdX8uSay2?y1HhooEI(TE>9N?-ZjIgP1*0;Zx&U~V{VmU3)ms5&2o~S<*w_# zfY9At2MuEw>O{5X%LvoTAUl1)3Z`{M#uM@Q!miFoJ8r-AYi2+Fn!q*tu*eRIC_@6R zZcTpH>AhZSH^IhxiSgHPB%84#VB*WW>Isk25Z5lXlKdI;9FoBv4I4{Ul)Kw%(uzH&nSWz^Ls- zy^e$`N?MVJGYCMWJb|mRp&6W2>W_y)$NJQY-qb+h$AW2!A_gB+@-iac<3s}j7afLJ z3IM3rv~A_Pe!hKm#jIwCtv95DEu2^BcK716#yqcLjMFT?SKZwt^sC`Gj(^ct*B>cR zO)h?=-;@rRj;{DbbnX`&zfLNKmeHR0aN^EDEYb!;6`=%>xT!JJ*=}6epbHisGCOxIJreY|CujsF^UCCqI zI#bRsrN`5i>cP41+hP+Hau5*1JD-O5Wio7*Q<$ou^;M$zxFfn^+p|^^xOhh|zeRO! zB7>MYd?Oq<5%%kXt`BrS3h4LATz57re1i~q=okIRUXNb9yHYf21PVW&ViMb|M@D22;BB{||Nx56(Ytmv} z2Gf`HUzW~vsUP}Z_4(?Z1;70HqYZtg$!$M>gn;q;N8NRO9qYxK7V?bJ`E}8b3*a?S z;yY2n-rf2Bd)rNO?a$Oz9Q5^9$4Z zRo*-I%nh%OM_$abVAEBoj6%UdN!I2AD)(V$zt9D=z!?Y{hL{SP(vL!lqB>|2T#z<- zi&M@QN03f3StXT;5CYlNCa6;U%cd*x`*((INfANd-RzcZ6rAu~^WY(fU*o^xGZ4viD_ky457(--jQX=0{)%yMC@$))~s%$bBtwU8@%Ozy3PE} z{fpIYRM9nY{8K^T0VyyBG%eP4$rO?FIu)GBSgNS&-!y16eCnyk0vWX37q$?SAOAcw zPOA|(mFyoY1gMtItRco{$=Oh|^B#A#9(yq#UwjX^{s1*X>m6c^&U(ig80E7cMjf2u zX-LN_cyuS=^{sLB*h?SQCv>sSAr1nDf->yo#=e2`MAo_rgp&tm@uj*l*qku6726?- zzPQ!X%IWgh9CZ(LFhFS|zRNCWk_Tl{a}K4Z(aue%Bo`gq;6xKx2byKU7szaFnUAT7 z4i)z`W;fdg3vb^ABVjH4wmQjaAfQiQW=XX!P4S>VBq=lCCYI_wF*j@;AcL zSIlHrr?=3ZhdqL6M=k^Oq3imLq7Mjsau<+B`8-s4(uTUKe3#pV-q$6ygHR2eN_BJo#KO}4R9vF|QpN~8x9s4&B- z$#l&dkcLdTLiLlTj5IkZR4+$PvGyLW{P&=TWaSxmtZNrtOZSG;HZwJo8&j>fEJvsH zlR^@yl%sspcY zx?_nE1p4E~4+#mQ_4{!2b=f(ThP1#aU&kS8@U@0BV;ex>&+%fpEFAK{bO&z&T}SSR zT2!pkeJc}e3oz89yJbJe0y@yiKM0xyPxT(6P4`#774C|K`Q#cz-1EBN(k%(`6lf)@ z2kBeo)Q{xWE@vAXwZ~?V2d)Fvk~mifzA3I(oNu8HHvnDAMRPE3zJjAqLsgC(Xr)Aq z400l3^HVM|so-kxE)?iAw=Tt;N(Hp^d@d%-udxwA>cAiTK9lRGZUX9+Qs39*5q^(O zr%BnKO&#U)XZs0Q=%du*aztF=%>Gi>m@VH*Hs$Ln$h&W>jsd=6;th@uO-=ZvF~;jt z;E)bvy>>isZn^OrOZ~kRt{aEFmCC!DY!T-!El6OKd#h#&cEg|n zEMuvE@pGHgmm`~Z6A7Il9pHc6*>+dHyYg=8$v4ct6Zw8mupEG(#((1a2Fu!7o*9> zMbmFmG^b)X^*p(ZGtF2$e-+ovpuZO>jkH?x+P5S|c9OE^QFAej@|eBicG(7t88;*I_9RdFGFMImZe*C?Q$6zEDp73ciS`PO=k?-HTRsY#&=wIg` ze}i7NhWz5TdmIp-O%t!Xk$YB*B&(& z=}R@Yo7h)1`uG+eJ9cQ^{6lZ?k` zPKMoZxiO@Szke>rSIus2LLy#And$UvPts7lePw7II7khGe^z239&4-4LnNke3sy8e zVLK{d!Ehy`CTLfhp3sUt*g=$@@+34ScSz*ywo3-x{FG_-|7fQG0yG%WI@QB%)*$a549Zgo6N2CT5PcNIaJ*w->%6oxkNn`;& z)Kgbaem*I1;xxNMWJS$4v=$fWz8+*v9=y)x;?cgV%83XSnEz%t8XROx7-y}?b(^|78IY&zI5mbj zq^8&9j{~0H286FMam+P2iE~ip&Ndi>DG9_$uh>6ZZnx#?K3BtcqF^c3hGTa0zAEEe z!ORN+;aAdXHe7x-b6&gG#-_?$G3*Aag<`(N^F?K|__>lSF{n38&kB`pPI99mI@ z!yi}B&ta%@MKkp!4`@XmRyndx^uvB*%u$=7hzP)t&2^+Lb2SwNqq!M>qtHJjks^VG zPz>ggpv8&Zhd33hK*Pi=5lod65@jD`ry-R?r~#}%Eruzf1&_HkRUy?R%C|A;a_hh> z3XQvcBZ;uBch1&n!BN=5IJC|mS6Fb6fU%ImgY*dmXM2b15_dp5<(C%S*Q*JWrih9+ zr@Cb?uvr!KvPG;$PAIUOxwh05eS>-wlGxxq<>j;3=*6^B%-JqTMTVf69BrYsMtX%Sn+#@l~ul05a@TdacMq>E6t-o*5ti2P0h zM)@MU)wpCqJXwKyz8slNT?Mq zA>(^h4R>VQHCz2eCa%!TqZn)KM9PiMS40vKM)>OGRdu9A6>OTICkQp?o*=bhuYkP#iU0`o9@``b z3{9tMV_bMGX*ngX*?08SB*x|HB1Pym>Tum42h#Zm6rYXqp?4f>>%WD#(G;#RLZ95U z^Is79-?=I4f6$N?w|BR4cCfemoK61?&MAowHVaA^Bj2-J?a&&Vm+d-U{xIv0;)y>> zgt2f#i&%wi0ej>YIudGBU;IpcBq z80S@V6YdY6=1+_-izmO9n5t4`!;K+Z_mF7RCbfj5jwN3E0$J7min|P5!Jrbn$klC8 zZW5cWu2*2~R58*8IFnPw6@+)?HiIgG`mEMQ-G5@}vj#i*pH+neot$trBacQo)OOl; zjC%8nWdgvl6hSu!l0=!(;QKn(GJS2n`T=2xmASlz4`R7~Ak4Cx(?PhL9#r7EUjAb+ zOW444dHFfq`1UXRoc~_!|6feS{~-iXb#rw5%rkIy`L8msuIum_WbiT4Zrfl$uwT-Y zEJBO;Q`QJw#;V_*r0sBiUAiBt98DziLSZuTSL~W>#Y05EAbr=@EEzv>k>3<*zb3D! zoch{et*b63vp1e{*e%Qr-Wy-Izd1NcN@7tWni1kA!%?s=+17vnYnLv3Q>%_#_4-=z zdKMfL09{9(3T=HXDhyj@IMuScEOML#iVWggn7genk+O**qB@)16MmA_s=JoYeXuxm zh_dceMs_AkDZLqlyRhHG2DtoCLrN(904)UuGj1WoYPd}`Co;z#&b65M$S-`{g|kjm zOFtS#B)vCUmgbch2SXV3=13`kg?|8iEz?`!7t;@G+VhQMJJ<%6cS`Pr6ME5M8^-GK zi)aTPmLALa-PMzd2;f!C8%vOPLaoG2jHP3#3%8y)FCosg%RR|Mj_oU~X_`cE^i@m< zjJjwRmX|GgcTCqctG-lQ@flvgw_!hZOXjx~#hmqMcM-P*63jVco>{o|=H-L#rg?{? zY?CtN>nslwWOI>r))PkDm(;c+nyO9r@44zoPzVHhkK2;s;n(W4gCq}LwX_4!^GGEl zPPB1!h@9X%Cc>YhCOxWtOz@~S>%3TEj^AawnStkRlS=FNUSwUZstZow+_)uC;0??9 z`_wYso-*?li=3Ey}8sK<{E1& ziItg$GLUw<~a^2?TjJ@nBA3PgNd&?%ATU+8-?xhBrJP-6CD9m#yJ2Rds+j9$^#dJ&re?|Fu{y|oHn@H8wFSvo( zFSoZEAfl6h?U{4-MzECf1Q>^KZgV)*x6A3YpMVut7tPu|$h`ybaBU*pD=8Mf;ul-Q zD{yv)^ZpW=|6xf$-wWa+k%Ulk!cPR>_+w#33c(TOOgLvqGM$S4&~_m`pY;zmTW?RF zRH4dt(X*#aLjq4M(YZ@{UP`1JP5tO72e>r#4XjY{bC}1e(8e+$>DDo8WucdTv%Jh3 ztF%P2;tTIcW+QU~y(U)#XRfHtv{1}~+B2khm@(aBQd4Hh_dO?p+t@kO84Pl)4Z_hh zjCaROFEU=?#9CvG3&avm(+I?04&x=_g?k2NT|;UwigGN!1IMUwsxQ>Y$}RJ2;X<3> ztlcA7w4?J#lX^u!4&3<^y21_jMA#U1xl$vvC=pp@xhx!0KbCBXj#>UN|JC%!8GQe! z`vd~GPm`?wU8N!T9~72<_BsC2^8OEn@88gnqoU6Y{#T3}ldg^O&M);dmrl$#5;741 z6g24s62BdLXxYvM+tQPnM5PGmFMV-n9_!Y=J)WzdsaqL7(>aazuaCdMj1aBBVWV+z zMneK|s5Oo z3GgKNa$&r5O(Zd_p@rM&6wQ8Yp~;(GYhE*RpgI8`4w}$ zKu?UP`0SshbFzkc5yDep)teUJr$#X0Pytyc>po_1aYrzE_u<1v;st&OA^ICZk6uQx z4E6fRY8*zSk^+hYaB3mOBJy`0$AWz2?~vP-tsUt7Z&?BFa78XsbE*+@~3{@WQyVI8IqPyF@@btk7P17iJ2v+qX@5Mcvf7>TgV)2;x%F* zF?%F_roOVKS#%O}P2Xn$U%plr-t+g$`{B-O+23SM-7|j7RFTK@%z6CvW=!$IQP+N! z34;H#OfdZiZ^qyH9g2VI1l4U^79=nPvv?91=_w!*Rb;GWz@I^Bm}PXcnmBMW7u|`t z0$DCyx$e;DeM@ZcX>3ABEWvJJKjU*r2}KKjGe>Uwo^xsQN68gObscP zglT=L?0U1s>MZDUmWHGU>!e4&^y zH0eY3i>S;e85-lo23LoYl48{L*mi>PGr=#i`B4~EXaG}AI@A|<~ z2SZvHUme;z5j3!Vp}HvM;*xSO=7R*c;8A+=;CAeEAW?UKQ5J%t4mWZ2{o}KJtI^Pw z3=)`g&C0g<@ny)o+V!l=ha&G;#;W;Qb+>p3)pQKhty$Dp#Xax_gMv9cs1xXu@`vw6<=_av zB^rf&rDgzkphu3{;xx>@A#tFbiIxbOR<<;~`6fFdnc630kQE+j@>mfxeya;(=1`nRbRMZZsrYISKJ!N9 zYtD`8uul6-p`(s8wzevBDa+K)0E zTPZFxd#z+f6IGQ=R2LDrQl!=22lQ63uvA6(T=!(D14Y3ldAQ=gCg$A*ILTw7sAln! zuM^3&6~j39E{mYJWE|TF&}W zsUN5R!6t{lJ~EgWSUn4bT$PY8L0kKNw7>#hbcgQ{-bK=Zkg^OR3}B*|3iwCtE9jW* z&%e}6g#V&u`gg+rpNP>Ejjhd0T>o}Q|F6fFqj~%Q}!MF%5}&##EV>j^ zuCN56b$%=fgnhhiWD{!Oz{v0Twg~_} zMwQr&%OX@K^jiU2luJo)_|QujRhI6$92#;l8%=-Jmke!s5cG@PFZn!6dbI~ z`kn1@!~yVWvdS!ayVB&>ZF{)IL{^Ai^PHCj?R5hzDALK#ZuVN6Ov|`o(BCu1pR1Z8 z5=K6iw64+5rnbDybn~vZ%||rh%s&9D2?+d(lH}yb8SKr9&*qJ`g$@3rN19g?4RD_T)i12)oT8n^!B7k&QD4Xbt z+34pV8c4&npI~%NyRQ;Dx~ko@LurOVk2xB@OO2;QvdDxM-;Y3WN|!1%hs4s=uxHz$ z{YfmKDub1~?A7C}4syh8T1p^lr41>>dJ+)c72HAyJI=-9vyzKPZ!p(}u;kdBtw)Hw z&Y=1>5<-2VrhOz|L%_|{R@GrTCGVTRFY7z(SP>B-H~4P2pSu1hCU)aF70pD|B01>c zH(>r|tE1;<%cYcI_w{;PPHP3^oZRz6R4QW<_!0lJ?nI_&i9XZImG zz*m?E5l76_1_z2;+XQLbQQkO*^>8m;>!-SGi9YF}OeUHxUA)8rrTFx7kij}EC_iN@ zvQeh4I_j?=Z;_NdnxcRa+CXweY=VG9S63l!aX=9xtw9OPRV)XCGGWxFE`kir(gKg@ z6P{|eEh8PrMzM=H!qrBk-FB&w4pMS<90Qnq6F%8M%dYxA5pr7 z*;X)a!DsVj3h}r1if4nNN4q+u<7M+R@S%BPER)q9Aex5|*;9&o{`r;=70Vns_Nlif zVwI828iC1fq;PlW-z>6pbsn{2qP1(ZeyvM(JjF@wM-XgHtf*+JCb5_6d0Qu59oq^> zln2ygOpZ_{3|T`iz+bV_v$cxT>fV{{OsWasPsE5f*2^(vj+yO`X?8aQSd{Akp7&2}YaHMVU^LtG>q1tD9l4}#e{q?g2HE!swcaLGG8rf9Y5?Jm>wr5r zNWB}RcnULfvqP>h~Q>+S*0#IK+F zX()mbkYA)-p;CVLgnRb+{y&9ut_quhEqJgM`S12Y>#=wui=o8EZ{%n}ojuu1-tsmO zB38UocRHt zD!*ifhGIuodEY>CI9=a^uSQQujWxdt3|$$`K4N=Y=w6#BmH@j!yA|jB#IC73fSMm- z6M{RzaCf9CCDBU6kUp@hpcezuLEIucNc#|6!Zy_h>W4p)+GO7S3p!8lO~B3y4@G@B z=EI0@;r$E3#jLu6DGW>goc#H#xYoj43Vi+S?wug~U&Zx5q1yjc3;%uUD%Sja*sO2` zJ26Z`qCulmNs0;N&Jx{$>a3Kon^$>3yr@AbXFwbxGL?sb6w8+f1iDlEZZH$-B({7;ChQPjaw*oVEq z?CG(X7aAg}w%<}*S93F__wCt2sZ;1)5AbWgv{|(U&pJ#2TOecrmzrlR|rjL zby;nxvzXPRt6Ynjbw;daT=htVEU+RwRI6t{I?XR#*ehRM1a;ly==pWsCsmYNo$v4W z(f7liD4;p=va_{0a$p0EtZz`w4CxsYRNtbtIj+=Kuwur$1eoKqX%F4b6AV}n^%#NK zm|B{AhD={6j`8(y^5nY~VO#_{VwUY`@+8Q`>3H~gVA+HLDZ)0{G z`n8~`E5{NnsT}HMgUIvTk(w;iS_zI?r)=hN2yGY zb&}eFa$)YqARBM(pQ+zxotx9sk{ec*^4e*{PwE*AGkdsSF?ile-ZxQB&5npW(4yMI z9HREJ2sqGHky(rdD$i2=zE-o1?6b@q*8Nc5BT6Q z<>vt)OMw1el>kgdPAz9|P@53GDwtEo!u;?!4!z+b4&tO~NzUX09c``|mN9IL04(bt zW0$C2-f)gpxli6OH#)vL`QH zfQ?c~35jPr+daaE9_h*ONNp|Bd^J%KM9LxgHz7hi@lnPN=v?sS`)GQ`@z-Ax*xMSp zh?^$KUyx#NM`3EUkI>&hr@?q4uv+AJYO;^U2`qyAe7xbw^hNW4KWky$CyPn8EjC7o zEXBhMxtjJ7EHW*E8l~!qH=7gP0qMcElznj*;1`NA-zE)DNTk|;Fv9*Kx_qjluFz}; zBJSjqk1!U}6(?fYf1qafMLc|_F`5W|?GyAvdt4Tu`-pDhAGLu82Aoo%h%?ZECn??j zAY)q4PY^tfgxvdF^VG5>?b!t?B}TTv#nCt3bC>{V8?7=U>>8Wc;9nvMjwKu-tVJtMNIT>=p+vwk~kR zaO>RX*Ya1TMToBoXf$i;h}}aY+(Y@M<$G}G(u9=D>K~Y4>EUT))%Tw?PbyL73TJHGR_s-&lNn(-DmHAa6|U6?QX4J`9#*zK2Z?@SF`! z+ZI#;uezVnhkC~=a_^QT4ZDS2J?R%Z&kAb|h@G!HDv+J6m9y;~BNTf&f`~Cn>nFd5 zcZ=|}<$A@WPbjK_!d1UXIWJ_{7FZnXbS3r(S8(H2@K+V$eyFma7Yb;U3II2LB|Zjm zAHf^I1bQaA3f6d>NIrVpBE3;acFPs*|K{)SK_2~k%KdO%eFpc5vdRCV@A-Ec{GXU- z{u5;>#I0N{|LJ2=thQml@D)W+VSXJ}n%N5f%BV(uUa566KVMHKAs$RhUcCm5=ZcHf z?P8DTD=IR{M-cJPQ0Vw?GHOAsWVf8Ype&v4vg;7#pyIgKlhfJk?EIZO0sbFgKOvZg zXG0TcFruBE)J9k#M@_+Ycf<=v*@Tpc7TrKHSkqYRO$cEXZ(i5$eNS#k+wVa~cBEGeJ=Cx|jpyA?fLO4Ka*`%^xaoTz#1TCr|XVk%j ztBBz#h6skYY$B_T(>B+cn$A;|-@DXwkV)>MI>(hvUB|ivyCcya0K~;hG4I0IHA)2n z0xbxK?ixBG4}?|#Wtq}dR&j5q9a##SIqP(JhgZ=pg10f#&}PUR9j8rW`bOM_Id zFdei}%?NZ*Cr|QQcrt%!p4yL49?8gFz97KuQk`rzqu?@6XwK^2JI~ie%wF-IU5j>@ z|4FR=KaNfRTdMspp%2xmajN*@p9#9MBC&e0K~1y7ma-|S@vB7`2`x%=MI@FobV|l{ zmG+5{HSL>bS6nn7lpnZfFqezCe?b1wjJA%YDBXb%@MLuT72ECQ@YL<+@#pv3qXUTQ z>bw(?hpXIPBMTHu@z60qZolSiYoXl3aFoP6IbD5E82JcF%0pPNDA}_JpxpddYIpHJ zQoFJ5QfX~7Xk{1byF(+bFheSL>7k|qj94^mb=zp8d~$DaN*26IlOG~|bW`tDopomk z(hA~TL#dOzMlr`0m5<71G5{y33d*Yp;HR3tY1EAN4%92fHtQQ4xTudcr+n@aYPj|} zmZtSR*-fI2pQmA7;8$1QB+_(exS)JyyLIDcm2p^);A4h-IessDJLeU(nGYkStMqMH zuHy-FJKbNGlalyPtlOmf;!TAy?vco9dQl>@Q;Cjru2rpt^f_cWW)TK^Uut33^CNqE z$j#bYA_1(K?vd6;Y#Fpn#0st#CrT~|hjI$lfN%-LFbYh+t@1Xndee$kBqHuqC06zu z)EevO^{;qwpMDgS;Au|cgB5`YLL4krL+HLHMhG@g#xg^nf!+Lu3H-4(9|P*{><`R5 zu@6NP6LFC87+pOmT;4Z}eN+ulJ;UsfZ?S*}j%|FYpY6_9kfL3|=oDYh%G1ZX(Yzw3 z7BjABw}N9IXu6%RIj)hoZ<1SG|}TOE&X!KM#zw2;5orJ<`R9_aXr8 z8|xthE@i$6+!nt0>Ob{8&72%_R%Z#*IY~J_hGxF1gUDy*$0tH7iepV4r^83Y8jM`B zf1S`2!Bc9K)}10#*amAQkvB9e)ML!-u^Dz_mNmE{zS0lJbT?Qw{PueF*>DL^zRe4CdW?PSKEU#cHVRbl=2Rgpu5)Q0R@+ z%3Zl~cn|J*gH)y#3Aq4YRDDRvE+bA!@Q|(h{l_8xlu$h@0`qe4X87$v) zqNv`$?yb)zau zmQ5Hrv>SJLqe>-yq)Pj+x&)bV2sp)FG*U*djiY7pKGdihx36a6P9wgF>H7 zRgk`hAvrR=VZY{*ijzGI*9ZM0X7n}Nh?P@14PrkW?vh=b31;M1TP#eW&p6J^t z*K+@JQRrde1^#vB&p!;)W>%}a(LR-Qb^l_R_V0j0_kRyf{u^-qKE-`zb?bf_q>c6l z_hr^eMTe7F3o7v@t1Br5tM%)K&|%2h*`%2UrkHZua_L<7?UV|BUea20YCoUf_qT`B z?~A3^7fhy|+VkIb$L{5}J=~A(b8<4Ca-=_gACFvvwCqZtxZxlgfiJSCp9oX1PV18+ zK;`J3vP9aR2eKTkEe8WIHkQc&$*arzfaLXMRRB!OFI(K)!Fwd8j=1nm2Ft;j79*WRKBj=crhs&up zt0fPgzuA^;deB8pDW|B6zUqniBv!EV0nz9!aov}fX1IRPCdh^Ih+6dIosy>uI|jw% zlN)9Sc+MYe;@G&!Dot`cv&%$Y&Z{X?eImdM{ZTZu^o{MQb<`PgVXKh zH}5uZ7I_n&HniaH7fQV+6t0=A z@i#)EexY;Hod^W@l0*^oFKOZz0~=&#b6>+eN^7z(IGpdwjAPI0)x>GHVRym&y732u zP_K9WK#9YjQHUcxlexWboM52Eq*C9dVLr3B>n{{VdB_Te8@|BrmPviVZF~2E=_Xre zc#A@bjaUV&83Jdi$%10QdiF%Hada%629lc`?CMW$(%;QZR)scL#-3stgZOu1wP9&@ zxPQqPA#^(YqA{|}?mr!FrPIH)zCRVoTI+BdF|!jpBjl?VE4Mb#fB%YNxQ`E%;p6E> zBolt!dST?mS1xm!nFQx}a_E2kGbrCu92FF=gx2A$u=HA?Zu|6(z0<= zoXuq{swTTnl0?b*>X!sH^QYO=$*oqQH>)&)xTo?GG*rhNfWE=?U>%zWe^tqFB{<4g zO2utc^}A>Upu8z|euVGXp#xPw)Pw_7@9?1mWkA-117+{jp#yb5*u;*s|Ip!QF!!Y> zsLbJ|+CBFY=3MKXBW6|pEnFlXo`VsQBjT{8(m;;NC~6z~juY4>ET00dhuA3X@if?I z`A>x(PFT*=7d%l++WTwrX6WN(dSS*@(0>%mBh76YroQ&TmELX=2d8H z4%5+G`$sVM#9zVOjo5G59yX1>v*ApI2Yht6AANgKstv`xhH|gZ>0JfiOr# z`km&p-Lu9GImgB&F<J2+B!NHx9pg0G|hui>NgMTG{9KB57XJ@x z?-(WNmTiGnrES}`ZQH7}ZL=~fZ9B8lwry3~wr%reozv&uK0U_m?)SzUBjU&R#fbQ^ zVt;GTz2;nVVOszkV4dJ|ovKA`(+|1>$a2ijxbExxE-c1W)?TxIS`ZAP{yY4O|L?aW z$KPDtza7l|ult+8fAfPX^rA+Nf6Q(%(6d%_)N^!l_)9|a4>_5NmFg$L_D&?C%3DcP z$jTv5st)w8$=4|Hi~r)4y_b(5v{KSU1Zb)5OyAnQt?DEE@!fk%&?7Pdhui(Oly`WC zu~rfc|13L?l(d%7<(%uG+2y>w^^;n9(fLxL%N_z`O*G}7HkQ5?+Z!LbqTopyVm5l1 zEUgdY68DI8!(lI;-sKlb%Y>#_K^ck|x%bkukQJ3=S%??9TGe3hHZlgRBDXEFaw}*t z!XW8;mh6z`d)A!DSeDIhQrR*~1_AA2UKB2M&<;JLv!QL*hC8av|4juC!dU*%7v0hZ zVnY+FO^=h{o1T?x{E(GOwr&ufOW1k=8At<>YfH~ic)fT(B`7iB)^zo%G9xOIm5Wo8 z07K)e+%BL|mR+ConXXcAfD-ja$>}Y%d9bW2Fh2QWMKZM&RoJ#){i)nE$JrjW$rQ!1 zJvR7GcdB$xu4qV?H2e_WX^^h=V_N13=zD&*wLJsAa!m&A8jjw}`+G7SLx7 z=f{7!&Pkmyg7zSiJj|Id#mu}+PXR#3cF*rG@=6q8Rvyelr}tvoKMwOjj-#0hwg$$yS3zs`WJP*_@bF0p zN;*v)HQ8)_?U=uc@U^MV)4O(RBFK1*w267P7YD7~$=%Vcq|hdDIoZO{A1r|@!K(`E zH(DA=>iU5(7OSpuKTb4X@OFFVV z*ugW+05z)PhvMPDxAX_I#mebk7k>_H!Xt_DSCw&GdE$*DriKpMv+?6U$c>C5nKl$n)5qBC#JvMrIe z1{r$|`W{gX7;Hh>=WB3~nozm-T_SiY?$l1#pbU`3!*q^G+f=jq;cCsr0S3=nr zfZ_Gu*`Mw5cto92{M|WbIw8-@66#@$sIg1py%vtllA}0yl%L2%c&~ZIpTPg?--?U> znixg@o5c7#Cw|%`>j@c|8UA((!h zgS`Ah8JV-fX;&bGvt$vAy=bLVM;lxglC;C6RB)4TXqnBZzI4{Sb%zVV*rmYG0FI+c zMHR#T?hDY`;)`^Wm^L^5iH-Eb~0<7Kgycj4QRJl1Q6X7T?P{&}eAN#&_@bF3WPr zftTd$w*ba)SPmQXKb<}OKOHlYHF&A5D=r$337TESgxUJ{cyx!h?YA+QqMtiwI1EX}UY z@H10Np6C{Pq1N78f~M$nCBteUT|)0INWz?_aIzRY(yT6m(5+d`@EF?Cu0UwT=`l73 z{hs8!fi$@ko`p zT~p~;BCjQ{PS!N|G|ks-katv8VM_*W*SIYrO*7k{tFfMOVH;uy@VzYPj)1=e!^yX% zNE*l7w3wUU^QA49H6}>}J4|li&s?sHUN}<}$C+el@s~G-wgX>X#e1|O+Wehip{^wB zjrQ<>ZBD&QQc3O<@Jq4e*=KAJ2e3AC3Gf@LN4Z!^kAVA&rA*(g=T12bsZF12<|T|8 zkor9AW}|F?uNXS8`}m=N=!ZypNQOxUNXALJNq&*^lZ+WBOM?I+Slh{5%Qv%$Cdj}A z(IND?l%-67TxqHNDC-!c=sA8V%PI5jq8K<1D%&p8)=SWJN>GlSi&D#1drMYMRZf|s zE43(ND5GeSDYU$q@O#(|^cUJG{3c-IB`ivw6QjsaOGD2;$*zi$6t2uc@YC22XSme!~ri_i(yQ`c)^*u>*o*XiNv9RZIpa~^B1?#!VVU< zBK0q~VY|}!j)-0S1#^z930rtwW%jo>ec@9Wihiw;%8xjn_YPAgb-nLA620+&EmJ)o z9+N%+Z78eao!uO~3J0PmuWA{%l~)%zIynQlIXX4go+ab53y&@{HcjX51>=QWg7ep+ zcFD`mE#Cgi8MA`qk!|$X-k~ZAd^C>O)Y+J(?SU+%SL)KObC2Z(z2+R{B)ZI6Du{Kd z)}>4O%-q=vlO9_f*3E$(rTgXszY3-V?`=$bX{Q2ovSB+1oL@m&FTbt&ZcI5ma-Ut| znyS8wVfo~Eyob*`LY{Z)#N@w3POb4{_6H*oYRE$S4ub*6purAjwq0c^wAze2fa6uLs`8brRX-fgYeR_f=HwjBxaEL~mb zH~BP4soX-Afwy^a*vA`u`g76ON00SA;?4C(#T%&0Oiz>qf{Y|}6Ine0Wj#LalT?Y- z{IC^;iV2;#CPF9ep*sDBS=t2d@`!90U}LH;;3~CKFR4{=%BW7ps15Fk!`#_UCTA(A z$uJk0*X~c!i%bHV%^W`uyPxRqUibGnHNBt$9yVDmeu=5bx7mU%^~S)y#}EKa6ED)~ z{4Q8Ozt{e-b#~u`f?)e`vgO&;jegsA1i-W#X;bIR~_H7D7g-*kzCv4Oi+S8S2pv4Mk<`l7?8fB){l zyETNv20og~Chn3>^Hr2M-3>N9?|Yo)MHMl2dftKF34$$C&lI<9?7g03^9~Sjx>1k% zRhKw8Tk)N(0*uTsA}QG>mlzwY+h(3+dL5@sO5-Fa|{V3SLnP1bD_3X-k&ggXNm)MWAI$P(T*lO)}Q%Qo<=FwSo9 z=<|{|{ea7s0YJu>JH72k+*RN2d!*^8pZ8eC3Fd6(J!=n{7h>I^UugV?m6#HWr^#kc znx%q`+~MQNJrc>aQ{D@WI981~;Ek3C82V{)Wm_WO#u1v5gKq7m@zZO19{fUIh&jm$ z9kf%ULOqU-$5?kznJpfa7tVVD$tLeqkjAb8o4;wzD&}nDhp7#SJG^KViERWSDm9#V z>evkWeEkE#b!aW(fAT~{SpN)1{uROfhfat;&&n$FLPnNGjz$VbpKVfxe?Qgct7xfW zDkH54@{outN)n2PDQ5>W6Lm!=`caF4lO-LjqYHrjnC#M6P4T#BJ~(Z^U?;tq=VDdS>?gp)+D>i%&ZQGS#M-u$gjzxDquVR^{mUswJS-O%=Qef7* zrM)C=V@!#tZp^x9LMi{)w1uH@&$J->n9xvRb{=Z3SVKx+dC+iHYev~Xnw%rixGW-k zioUtWai8vb#bG!bd}cPqJXq1nJU^$IB#PQ0Og(bot4@i-mDn0V?~16ZC*N%OXabAc z68zVm+|+D#1BCNuJ9KuVh{1F9c(`;X%JAN4D3v1X#N_&{L`Mzr(NrU49VP0BiT3`i z+6wp(&RQb}#Va7yd9<})2>^1GTI~L%b^V5#_~1gUxJr3K|JM1}=ZJyPnV*99h&+9hiG+bq*>!C3>G)MV5o$PZnOES$>TRn?YlKl&xqRHwd6R0 zxdNLk$kLV$JO!-SW7=}WweKf1uk5i#{gbc7BoGB_23T^=r>iIvpq~c2u2h`Cl)<%e z;busuereiIWjA}Cbae@ zyzcDU0xUe$LUtGs?1-LhfmMr>Q*W^ge;(kYZ}d%t@qm{{+>r=Ig7!9@T{b!$-a zm<6|bZzgc}YiOa~3e*|Av%ocwW~HjM_RtZf+&%Q5lK5%$mB=-gzbB2!f*-S;^kkph zy>Pa4Yz00y1|fc+(QHrD9pq>!aYR0>~cr`2$YU!L;{ zq#~}9M&m2Px!dv)P+wYDP^TRc^>%~-*d%$ha#yW+sd~P-%30kB!CB7Q!=$uBq+&LD zBaD$Z|7HN)W>=4Xwdj|SRuCMxgmAt61c?;I3>=0qS%YJ&n#+wA54u7rMe(Dma!P)564d-4QVlWYr?(*5 z62Yt_oKz;96b9np2Eea#gm~?JoP=bRA@74N6!5`oLE7XGljO%Ke}t%B0}+^U@>kFX zJ638sapP3lL8f6UxtbJ>AQKTIez`jA+89K8lZVVr7(V3b==pJV|K}(PP`nZ2FP}=B_5c44%L@N=W-ePM= zo&~znEg2M5J5{Wc9)~DBzwC74yN)hQs5mI(Z0~Nm{>yy1&;Chts%&feQ94V=`r&93 zSG-vaLEmhe*&rz4Kv97=iQWYWg>UuL!1*=UOk;;vQ<ZR zqznt16Y5*^8;+}5gHdbkxjs}D{ENF+Ty_a%B>+xqC6;hS3Df|N^I&C45WDm-}^ zEx52~jA4_mZgb+OGo_T&6mIgrZ?q$i6F1AlSe`4p9fqch>(3oXBcuQ?xa~;#m zW7I^mvaut7>K`OMVQKqfhxACo3(l|ruG$Y45=y?Tv#H$ z-cQApvnN;gxDzJ@S@^ICUwcU%dt>t(@W@9i9CqVnMkFlX?1F8EMkK6(FYhe9uM619 zly9VXb_sN9Y$UlE&n*G=%(T>Tb|kvlIWVe z9K|i><-$4%-Y`mnFE|i+MGL*L0v?2|uV)Glk)T|nbJodnT&+%l8Tv6Nvbfo|4vA@P zLz)IAf7tzE7UJoCj5!rG&B;aLNt7K^ECBY5txEG3+IPG{HML1(u`8)_6lhF#Gw@w`VHvIAxGX}x zG?Q?K4ZKFHI#a;SzNXh~8Ru|AbfzsF(h>C8RO78FD9kmOpNTH~XVF!KVd~FpqP^jb z-{4C;x<)?ZQ>YXCZ`+IhgR$aY;Ol>@L4Su{^{U@oK8+RM3sMYI>G+DH5#(qT@T4^a znw7=C^Wr6|QHko|D{IY;|lYjI=6WAEAI&3r2K3- zbOHi_fJc&_#v@qtb%Qnne)cyCSxyMuV(XF5ikKUd5T8XV5^g0zI?dE%!oe(Vu~1Q9 zR9>i~&W%-p8&5GBu{~jCK)<9%w>njZDos!QwA4kZcMKdilkBkzXUGV(v8Ongmnx-# zEhg?|M$&xXmaj`v81LPC3Vo93CPu ze>Gj>WT3AArv8=?5i5zBy}G+vCRKrScImDIDn!&NR{-jvZv*PKi+fwI6_TsSeZ#X{ z*JC`NPj0=<{*>^t%qI83JwhONPIUR9VfB=>F)^~N-czf|uy-n6$ixa5bsPI0KPcCu z+ZF}G2sId1YBJD*RWl#GaiB2a%bKPd=Dj+@;o-6Og$KXs#>d7^xgczik)ks<`!D_E zesYvT^>jTumF}m=>f$JS=XMpO1*wYKzGG7}VHHs5=67X8c;mbV512u&MQM{UrLr#VqVB7d;;>B|p-E|%v; z35WN4qu_26K94&)21Uwi&R)t5n#rknEVn8O3J)SsK{rHF;E*>x%4jA7Gmnb}Ipz9_ zOr*##P^_duv^!duH7g?KeMfKTjP9WiRqzxJ6{vwjsJ1D#{lRhD0U(cf7^lLMSE0@;)Q$kva+ry z&T$0fz-GsP%0AsC|UNE}NEMg*doMG~k2C)GEL?2k~r2~n41h}bnq1j|S0 z21OA`7|!+vfr|%=xGNlM3u@=TZj6z9I4I9ofq~`PzwYu2`2{H?H%aA%hdFY$sTjM3D2xbS>u?=h#O?X4T?b%UHth4Jf;wB zKRmWT;tb5huP$r$-WEt4QoKAvS84tf+kKrF_B!6z!*L-4r6z@B2`YyBI0ib$Ldkw? zGxlJaDS=t>Xu-R`!Sg%z=$`UDRZ>!a%t+8;(kkWQ#EQUG7BSM>dH{s7?0m0w)DESk zO_aee(n!7Vtx%W8s#C7z7huloVG8Gt=);pQklg9N>?YboTDj_&Q-a1_2a>0_!n`sqRCbv( zNjv4}mIbSy=D2W)xIflpT4NZl*(ZqT7ARvbHuhZtUEm_a(5VRz8abG zsg_u4rKCAa4AHlve%$@;&(RVHwFJR_N%L6O$)lI+yJIUaBb46_EChS_(1d2Eec3DD-36SDyWp`$;K>I>%$DaeHGR6wGJ(Es zGQXX%1XOJ>U?waXO)vu-4r-O!q}p?vMX!qh_-aiVfL$+VO(jtJ z#dwu}-g2pQDB+fz#Nefy|6P%T4BUm51sEp+!WS_6@Lep|lG>!wVm^kBr?JEJ%NBr- zL&|r@JKKc1pp!oJWiGcOMx-V1-)o-kC0nHPb46qRjTigZV2S;ITk~>;#zZL^ywwr|RzSLKz&uOwAAw)4=}z{z61Jcp9hmPP=TP9fU)bBHe(Oa%3#n z3KRv4DRYtct?T2cUl5@L90hK{&er79{OK?w7VNy`&ReCVy%kc_$QLDZAndfCu0_)| z%n2dy+u$;S?>MM=<8CwHtZoe8CA~=6URT^#ZfJuJ5qUCu+q|jkjcV`Gm7~{t=XI8j z$5yKxw!wN+^PyIxteibUxb>c~nDF2*iiD{J5X&i;Cp#v-$nU`)%LH3bzWveb+%ib> zKKL1$-~G=2H>oJ}-vm#E{tqDe7l!Oy&p1^UqT3rvz zktE~~`5_?MD}SLGG`6zTRzEJdUxGg7h7zu~JK`|*{&=u^ec}G%+9&wQ!gAw(^KT$` z)!-z7;u)Z|QXga=VR7C1718v983b2%Q1!=KhE4EzEID?C;e^`fmgFADYAeLf+CwR{BQvN}qzEKT~OfqSfcL z9whJKmhzQhkUi`xX!*u&GQ7tDBB~Lk(NzQx>0n$bbR(3O`8w?3&e&{yCJdgJ-0%Z! zOa@z>dDw^BBlZWkOo#Kc3*HT%uWH>IPz3usa@BDCYDi&rc~yOhpj5R~dU!H+0lq;9 zNGQ1CX!=)nNU}h|3Fi4keAEjW1;^Mp7vIJ~>-81`OJ4>uk1;YUp9e3XW#>?IFvqld z*9ht)FdHrMrN5GE)JNzaS!Ju0S*tbx`A0dH8iC0TgFeSpXtb=!S#($|LoXv|OhN3O zDM)wqq-7ElrY|8@#gE^1e52yM*IQyZ<|eB6?M zRPpN(5PoVt4T->QhUJa<>k*9trq(R;@^L3)@sZk?hnmk2<=K(GPUHZ5q z=l77Y#IrPMK}PPlaAeDsE2j-dONHc}^7E5Snnl%sZThfjUsthsWbK`0}gS}R#lAL6GKMfH6A=9JLE+i3vu7W$#;!b zdl=Ds(e!K@ji7Yp0(%nip&-Px&wbAw*6b~Jj`>PkK}FU`At^INVF8hjlvzx` z$>|g*#_|9>6$cqfWW?V=xXa0pO;;g5Og~_@4(nln9bg-Dk&2(++JstF>Yr@S_JTfD zIzPZ!7691t!p|~RZW0ZR!JP+j-}d;`PBca!)G=_8d>e~Ih`2j@RL@84=ztFWNt|uA zz@wS40e``{$BM|J5Ke}spycx0z|kDMW+n>j*FA9isD9+&>K}r-G7gscu}>R?+D}aK zf2WuK&_nj;)AGNk)Zb!{KcAP3zsLcEK>y_M<72Nk7dAcs zXaNa)P!8aAn=0wGEB234gKbP3;+qashfQf+1c?YuL9~vmvRTON*drL>ZVSl$=!4f@ zTNaark`0P*!sFMOm|(1vlhsv5XBx)jRoD(@q*dGt_6!)?>>j=KehTuYhm|`F@(t{X zt$O=@IcL^}B+cc$6iBBvgY7wugrUCFfIlk*nk>#H?QVnkj8 zq#h@c4?mjmlZ7eafNRNKyP)o!{cVgTl{gwlh{iR1h0V1@uMUy)d3c-vCgPFE8LIL9 zQhEu`j&X~8ii%rkW!Q$#Ux-<&8v8@fR^nrvv}mh#VG0J7j?^1p`H+5EbM7Z5_-uPr zm?@`^a%u(p_%?=C2t+`U@B7~caB(KqiI)y_M$ zTnlZr6*6z$x1L{?(Q@i7oJn(funzmqvzkMhJ(3xS`38*|CnYpeuxFEK!8*-LCo8y_ zAYL;Dlc1z%GFspJK0cYJfckr}pfs*`#2KNiNWb#Xq*VbNY z2kZJS+Ap}*Zk1#LI?gZ`WZV5-bM^Pn>n9&Igvoapo@HC5M5is?BKH39-Wqk6JGtQE z>b$zCvn3g_i3&z*pDkVU7=zXt5}qQDTt7MZ6e->iVrDlbg>)v7y1!w?1>1Y3?QpIx z|6skOQSHjVX3_BY!b};Iz=&QI;;q|MaH-|7rK4E zb@WdyoyZbClm>_!?8VK}Fss+A))l&B+}?zI&i)Yr`)$EAFFwke>_@~RBaz}!Cmbi= z4dda|Pxy#aRUp!M4+xHF3S)Hv8(~x0XL`QN_-&La&O)LyCXkb%;Q3)R9{B-gVnKK4 zVrEQsB|2mZIz#R0*Ea~SPLKx?WaV6eIlMU>VH2PQ!8*IlJdTh)8x@`q`V&p3D>PUH)dWfIV_aR~*hz(|k=NGT2&EaGY$fohTmpbB%{ zMr)?K$>7uDY^|uNs?ijuB4n?K3kq8PY?VbiU*+}xRI{D`+cuW}U=jIen)~b6^=E>s zSGD?dg8tO>wpk)0P&NA zy@fWd&C=M>ljOlz@evDFA-NY28&=WPpH|@!LFXu0Ru8sgUe8=imLu}AVx`~$Qs)Pc zO7&^%r6Uqk-Gr=Kq}c&rEtMk@^C>1PphM4{$|#;DmAv`rZU2*AeHOm993wQgqU1i} zOqFz@v<%MkCdJlok74NxrcGY(OtJ?3wz*kMs~ zyK{s+9L6jPv9(rWny_=cKAca@r@N=04b_1R^k%V!Z&^aq2p=eAbjyR)M;eFRXYE$I z;_>--(L&GsjzD`nTJ$j`jqR3PuzOdL7_1#|0*5iC^kt=51!f-Pu3V-0w6m_)0t{Qj zPo4tcNNI3XrP5|O7&)!Zy~F^ltH|2U*b%JbkQs}cq)-D<9h0dQQmBOL}!^&61 zWTo*5nsL_^dK&ml<@#M#X1*>#4eys(1~T0?`uFstxKL`#4>5}j4a}qe3Lm#Q-zUk) z(IO9l$A-MMW1F$<$e-cHB->^3a&h-|r1CLv7wH}9%o^$=Q9UNRSgO zU$tju6Paf7jjJIqyn>0$yP{c_+#!oJJG8=}j*!d}M43VBQ^!sWe7pOVZ9pDjw8)_{ zZQG@bYnf7(*E}4%){}qp%UruC&!OUG`W!HVB8#NSde#6hggiP(i~ zQ+FJjT;kDUqLl+J+J#E&8Q9_&s!u0^+vEUZg*2%%RU}IBs^!cgbvRX@AMajfCrZTP zGfb!4nRY&=Ko+aHsuE0vagtE5C-%LCsGhkVNVg{@W5(WmA31JKCUbf5G2A+iTH+CK z1IKaCxQ7#t9}8L|4T4)ox%aYbp)C(&Vi!m#PEn5hEtLa`5>k2U5!NW^0 zlX5YW@vMPZk(a5Rq^I-a7?yzwY(ZzRw5hjg#DaWL2YJBTc)NX8J{$_0C?CGci?{lOk$XS2ATg_0Qj%8#6q7c6az<5Cp~*Zdp$GD z|LL&!yFRvDb?i4W@*%xq80#n@>1!UK9{@0;geC`H1#AZS>EfFZj{;W~x67R2%z$W2 zl7ENT=|Z#W%9YvMQ^}k@gA(b=W$m~nuy(A%`i_Wmk%m5P#-I%IOMidOt@+~p{G!9- z!sF@br%flQEgUX!6>=Q7k$WremZe?Y-FHe5ND@ z&0+hHe!2`k7)Ao74r`V`c6bido7Fb_p50+!_yu7#0!w&d_!|HWtcFc6Q|uJw17%^= zi1b){s>$~!597S^R_a|nll zAHv8VK{j#frgA7otQ*wPY$rojs57U{am~?>P|=M{B~xdy>mH|TWC4RNjNd8;;?p_s za7(^wX5B*y_fB0~3e?uujXy*8I%R@Ms#xPZJ0Ls}W7Kyjo(i?6-SjDpE7cHqEE@t+4BBup1?^ zo7wkO0UBEw%{q#Naa5KM6f0uP1;{?{P~0=heHP!yH({Gylwpd`mQyy6^tHN}*~?(( zVCt=`)}|FYoy+MqFV9stZHOv?W!bf1Bhli~;(4w=Oh{$%(^!AZE^X0kr0ffmZx(3= zIJ6U3gRyA~<2Yj+v=#B%pKLC>T!-S1Dp_WJKO6JzPN}*dA^jyRn%hqkQ8I z1}hMEIH19B2z2W$Dx~zq)5ArAheSZRO7*8Xjm0xa`W{h=Zm&^qa+n-D8Ik9|a24n; zb1Uu|R~c=m(DQ9wBX)g28l003PZyGRhx0~w<%p=0W2P+bqAA#gs4eUPs4l*d+xm|D z>o?VjkI*^Cve_&fTTmAXS6o~$w(FsL*Igc@Nu9f`8WN;+GacxO3cJwO4U?U(ZcWA} z5LzSV(@2MOe0hBN>o{xYT{g~^?QUs zh|@IH^xcJ!rd-^F7^5^zky@t_d;zfY6c^KxSLz_y-)J(m$`r#telEm;3Z;ea}V!)qEiV~yvNlK-XC6RF) z5qg1)Y?6%EEsg}pj^3mkK4pTU_eVopzc1g3IDE zc$R5NlgQo@hr);{N6=({7QdP7%j4KqgLtyfSM7Ahkl!iJUCpEk+orxp)SIHV~Vurq^7?v z!j@rr|HJEi)(K+n;@^v@FfU)9iraA}yY{BQv}Pndyy zec)7O%#f&fL?{IK)i&HluXWZb)_rqSSY6pdVF~%}#U*XKBM+WyxL-huM1u)t!LFt= z9s1)kj0G&_a3v}mAXQjoTRq%j{P!2htk%X28SlTPi3Edl8%6bCTVq;P5*YM0-=>GA zXP~}2>yvsbW$U_JS*RX#nQTS$vC()K!6u5fZwjXiu?@Pe%&m?xG$lndl0AA0PnwbJFzwSUV)Y0{6aDM6$+Kk)wu-#l4J>B9 zKRRn=Q7FMq5ozY1p2m{YH$dJB?h?2gd+DPHwqAeU!^tchM#F<)ssSZ{rNM>RkdmMX zu=_$QC7K|s4@dY*6zNe?lC}q~mA(E!eoV%-RM}HmmQYBi?SQuI>&RU2o=Oe0bR(m%6X?@qWVY!ow+u z?$diR- zqrjTl%x!|cEI%9m{9cT;)Y97^V-w$e?R}NVWa_K#t-*={YR5k=ToPBSCE5NAJD*W&m8P9 z9UX|>27}|4W&sJ@cDnkDRZuoU0^}6ff~|Ff^!F%4LvhXlc8`Jm#w8ZS`=cksan8#& z%SLNdhmqZPx{CLS&;%Y&opImLijuT*lD)ZE*dMR*m3omc-z(b4fovKr+Mpiih?0_7 zFCJuC3Rzn`YGP=QZ>5YY%-sesDA6kTk8m2PR%V((wTek%8;e?T9B?XAmP56*ovb8h zEJT)}r+>t5WSLTQQ?{A+yf{UlDqxZ{%HAX?dNYzN_Lf*9yb5yL7+1Uaw#?rrKEav$ z+|>KGyG5x@=L5~H@%s)Ew!U;(?7qHtpsiap^-eG)p4eIJVB8D^Y9jGFt|!vX&nVqo zb&7yUe>sGCMoJWZ6%*S#D^WC7h1T}bx{Hu?Fh-DJ{hYO?vQ(zB80{zA(!v*K zyOq(_+L#MBoU)Vxx`X&soZ<#9=#-=6C`*g3LX33|;eZb99>*qMRIEjggDg7L-ya(a zYbz%Vii%Fd(fnzo06$40qi{veqgYk84Rv_E(&JUuC0FgI3|tV(JQj)m$+Tu zqQ8z7hKV2}B7Ivl#WXd`2ld=`p>-Yb^%-Yf5O>n9?&ccs?IU{LkLd`T^R_q7MBsu` zkR!odnin8}D1qgdLEQ~2H{vZ<;+lXYOJj&ygAJm6gAd}BrO3JvL0X87fEzyxJr=1O z62z~#Xgi4V!|ci%ZGmKBB=*qdps1s>U|dAf$xmCW3ExV#XO!ygCIkI`_!0g7>VYfp z@`;(52dM=v*afZ`<_X8K8!)#=D%sdU@*WgKEaquff7g4`zD!6!86td^3Gl8G8@Mm` zKW-7oCyB*A=l@!23J5f!p)13Pwkxrk`>>gVa?6N{LYdcR-=MPChUC(o`BAlR&m9wv+ux>p2&9>Yc-DY{GX^Pve4~}mt86o z#8Jnmy(UfJ7xjm;>0vzJPzg-Q^e~=Um}np{R*z#R&CWrfI$+VlFNcSwE==+=b-!ERXf1?`QC<)Bl+&J`|KwVG0{djPYk=ynvf$Nc$F- z3c>Yas5}MF##7Vbr``kkC3G6)o)>jW2UyK|M^K-O&c!qd7K%CTl(eM^(1J`}*O#lg_3SoZ-vau>oZldz;5%Jmw1sIm*~uZGnfo$z{L!l7Oi^ao@)-l%>pvZ8r=bFVnd9c2@M;EId%iq?DU(!P)1FD+u% zXEs2b^?c)gay&}6E}eR>))39&))0wz*eHuvMI39~B|GRkpGLzZBeU2Z9|SyMXx^l= z%L`Ac^R+kawJml+DvdmwmTs7X@uqz`4WOhiFL1Y0fgfT+sbVx+ou))kxr0~S_J;t0 zy`f+W|MP!w`L_V(zjVk@(Q~qNR5UO(veNr(Y&JGC`Fq_aU&TuCvzN%*T0l)r0TMn& z=!9|(&Jwk*5=1_9dir`A0V7Z1grwO&V9eUMHd~nYn9X@$3ii4Cr=AI!<7qf=7w(?x zxUo2ZI8q#}#|68~g;(ayD)+(p+sOs*JCH3rJ2LHdODMm!wQfbyYTD}Rwy}1%9|Z8i zlDZQ8cj8Q+v~o^M>e>W-i-4pJ<>>twW#FHbYKUNH?7rPk)Lx6$WZgyGXPScj4rycL3Ci5bo7tv_Si50ETCND$DC@ zbZ0>t+8WbSS}8MF>h{bojbxGdofVQ&FS*|&1Z|kM@@lL;OP|x z*+)!Q+fy+l^a~MGMh%AZcVIaqMkCA+3|8?_v5Z#g4W*3u)!`m?HiyKj98nMj4f!UG zk`4JsbK=X=*M;S4@s4IN-A=L?iCZ$@Ks&i+z7^=4r0kl#v0-}xA{>-$W&km6oTX`I zYxIi`pslOYKTH!WjCx1KMe(>yrnJYB-HZE53T4`&icbru4jCKj^>#%)*+MHUdaEG; zIIkMM$L3~S2U)trIcb?k>FDOGdpqMSOioquQ@+yHxNW;1vIRPjN;a4m1UNg^O5q2V z)tDtV*?%~^5lrkdiLIr!QdeQwAWc_?ixC!lKgLFerMf74tbWRDa1(OGy8IvuB%H-Y z{MiN;c{zGGAYnD2*TUD_=JH69U3uqfz{d{q^db%C z(JK6kI{VFk5NNFoggmGPZnMp|Yh)LgPD=JR8MpLCCp#!McscX~L%XmeZM~DfU4k$^ zcDG$x8->5-du<3H5W)nUXJ~~4YKh}o$bsBE%;XJHyDV1|ytx4o=q`EP%VBO`IG!N> z-k}zb$&qvuK&T7du<&=F0nZ*M0Wdiq68Z*MCtR;mOaBMEVMgu6!K1mp3*{Uz`7hrN z`&pJq%qU%f1d-u>elLHpjU)p?g*MYK;p9n(MKe%_!noyAwrL87b3X2hr%2wmX;e|} zA?%%l#(7|25_ku4yGT0R14TeR6dAis^2}fGbZ7p5NPEZVO3+bwr$(CZJQO_ zw(W{-+cqn#*iI^yyQ};3Irn_;ef#zp-@lCf%i7s%J!`HBhDYf4Pz2yp!e>mL=Mq|= zCQN@x_Ea8@xgU;#Fpk|M9N(MbkZj_R-q|?REFBAI4udcce)2oww!|Sl91dnooY=g3IIa=R%=xFC#Y7=+` zSa{$OyKwssZ-nz=z9i+$TpFM{*jWKN*F*2<>}Bt{yz~4i_+iV(t||uH6OsNF(f&us zgR-N6t&`~=+8%%##$O>6|K?4A_AkyOe^ZZdHiUwp_oG<^)#BAEL$(YgS00jJ{FkQk znC=8`77cg3NfRKbl+t@wpnd8B@Ft2R-A1!LXR9IlE;ILEcviObQKygp3jjF1n-f5W<#C^sbp&5a+rEJ~Qid0g`>NWwnv1l=mK&BqiCbv0~u^SuR zXe|1%6<|Pzl|!-|&wy*KDeZRfkxu6xvR~7&-ArKkHd(b#kKaW&i)VGHY3CrPOt0Xl zgk>660WTzGr)R@4x$LFT1I~$;l-0Y=no9GX@Izw6A+S~)(mA}@_Syf0XRY~xrto^y z6=#c_>%_G!X0So3anNXhwl0iDan@=mPPp(zXRMaP;)-Xy!!CJaQ(x&`;Plukg&2*V zb^;w|mLtWyzQl0`yIkViR-NTW-4d5G_haJpB@R;_T+6qF`l%77szYd%291jJnk$z%Uyw_hYg=nsIg&GV z)D`2rzd&O3k7~)*VcHJg%WMlbKLq-5OGUZK@Lua$e!V>78xcxt!t}2E#YJM-{mUaF z$iQcu`NpX9Getf@t*oOYrT zoTF#jman@sog*mr1e>B(X!vFZ>I_Jqv5vt)tiralX?o7$BqEI4Ejs)ng%Qh+wIOna zUqK9KiUP&+6fo(=@-&a(L0|-EcfEPFo=ZY|;Jmbd1mg56Jvm6j^qGM0nu?y_knkQ^Ig9 ziW!&?ay@^T(S^;B7KUzKK#TFq$G=@Im`gjpTvb-Zs9c9J8^H@b-+M4Ii45TbM}~^Q zKixC)`zsa35t>4AFVOTi+nO;5gw$Xe*5bU_bj>k_2p zy~jbfxGRAmOZLh4(A!Q*&CsY6Se@}r6-JncZ+jt&g=r=XvbE^EDd=n_QzA>Y5GQGA z{miE9I5hexl3;~{_L99#tO|w@DFul~bx~vC(|?M}4asS^k^zlR_rH=I{?C{CKY|zk z=RTuk?`UFR>|}0Y@^AWcv5XWXAXUbDzeW?p6BuCy6wOxT`U~w~Fj?4zdIdu~DP>m% z6x>e!Ao7!Kmcfsk9dF&M5u{%9i%$Z6s05oCR=9VJO47%v^r^Db98&5X)_T@-920}M zX5_xvmUpAHl@@#r7VoD^!ec>GKCo9IqK3 znAAFWr*vg3(Dd#8xVr$BtXl8uM zN%ce#RiwJ1Pe7MApJ^eSaTzb={E-v}9)UER1H!ZOBB?DRiY0a4fl{(rwpFW7^(Xi_ z9K=QN z0B7(1`s+$@H)@0A{E-d5^|~yxHNt_}y&MPqW0miX_lFU7oXrL%$kuHx(5`SQi?1kV=VlqaEFhOfLWJ9`oCwfAwVd3Lq zpg?AMEi4p-fzI4M;?g|}1Xxw5Y_Lsm+j;zG9x}7pxPgg}tB;~X&8qJ`{j48@kT!49YN4qO#z_wT7 ztGf@d0Q6Ewzp5oHirdO9P}(N)jBPSI?oxK$10JO1Ja+`FU$9c?tJ{&Zf8;YhOvwo< z70eiRH;r@A?fux0s4i(a@HbE?6XlS6T`U4gX{<;&3}14mSWO5+?jPlutfoI`G}X*b zlw=8HJl9!XdS#t;2eHzG+L<;0)5=qPYZ3W0fKxREjRCMy@2P z!4DPyp#;SMJ+*AJa|1xeRBmW1$kss)79eti;wXhO)^qW*sICgVGtjPF^PoZ>FAE{B zi$7ZOKo&a{#Z5c4Z(_~A&uij*Thu8YeAj+wPaV@{=L$426Qh2&4_s*c(QpGKU32)u zGh8lf7RMX|>Ar)Je=m%P6!`Ni4L((fLHi=;8&118qBGpZ(={(o$MHMZ{W&R|MPw!1 zn1`TwR1VvGX;`ry!7s${>v-uN(Ul(*MXAR=2s>WFt|$`ib_D*|9uk=p^IIXDTU@+5)Jj&GD zy3aC9pD=l$6n$_KvY{2HE*RC=A65pa3xS}rbZyG}Ygh1-X4wI8T3T_Ak#edOIN5*3 zX$p^#v}7-2a?gp;EG^vIfI245JpL)`{HxV3CSv1r_LV(Ze=+R?Se@z+cwz^Y-8yaER)pKuCFnCJ6`Qx>=c>>+(wVs!E7Ttx{L}X|Q`{0kroC zM_}!yEn(N(yabh7R&!ovQ))&$qvvX z2ggb+%$D%`r$^^gyBYF>fciwlQK}R~;UAEujt;HHUwrar0mbzT6=XO0lwZ%!^SmzB z{hedQ?uxGF(_<}0A(Bxx0cNVA33TXIwtyvWYe()j#oeIOym4@8l$K-8n}tA3ZbIo| zZfd`&s`w%87>X#@DM$?445Nv-?VBPL%Pk>U$YU^U8WKqs(TM#5j`U#RPH}1k92A|5 z+xlDR%_Cb2d;v#78)|oB-}>|&=ksFHEC(N}X#8wfAqZ&e)2lEy5REVfr0!#*J#L;dB$vgq;<~ z>(9KBSwjtI9mkZI<>himA4Gm?_ejJL9zpjDAB!P;k`qCt56?Pa4LYjYXYw8`hGm^d zK5Hj>GU(G;b-I#j)a=&YIRK+Vj2^XH?^X4WQpm3|Nlq#az$maNk?l*b+@#PyXh};{ zBWvO7f5g|XqgcK)86klucDywpfYWFn5dhs-?lV|oWsh#PTHMPUjkcrxp1OCZs+C=U zO5pzO)cr@sK>v-h{#B{JsIh0NNM-PI`g@`|@N(=diXT9|vW>B*NLle}iR8qzF%4AXp5HG_`6ZMFYZmBuf{{dZsDsGfY`$*YSJ-HS?yG zJ|nxvy{e3_iFe;kHxn92m%2ZBy2&n>X>B*Dmy_r!$u8()|0~P}0#m=<9U$f?`MW>C zD}ASAtty16MOA)nrff+?@3;b^bCH2ZsI0X@f~}w%h<7h#@;Usm?3xzRVQ)(Kw%Y!2 zbCc*mWKAw~NV!p4q$w}?#^oOW)Y$#cdh!t1gurGiFd@tm#%Ri=!Stw7Gg%?8Nh%18 z@{5SF@zYN78O=LbIZo29g2PD-6Rp!Z18((tiF3&Y5`yIF6$cA!Ln|~ag$?)6cRQS> z37th{vr)(rRFSyYAFWgi3vLNlY+kikcN;uPyZb5(W^b%#?0fCFc!)W>X^_5sw_g-| z>QB=qR2_z%v=_=T)7i?zm>OgOTkk|!?cBP!WxFW@_vY5~nW~UgD<&?;xLWzC*1#6d z+g3MC!rn&2Aw5ra`UT5{doQtDUxM}w&ITS6)1?n9L_XmG6s*x8XY4+%jX1vNE1i$levR68DTKrllMN24wwSNTxlL9Ti5MV8k%7 z9wi7dU$?63S1ye*mNv~ZSi5RVuDxE)x{3t;93U}#D2W2yAICz*OyOw=S*KQ zTkpR$^#_iMWR{T1T|c1zzQ?-WQ!a9 zI>Hv`)mO^kg>MsA#65;COAx%U8p(8jkKk==A0S5?B>o)7D(`AgbSpc&T5xIX%-}+{ zpPPUKr!)(q@IuHQ5$2_FY$C%xvy9#kh~S1 zI1pD?>xFniZ@ScXxtPGR6Zhd3OTqI@;mwT!tAO-W0qlF&x?ZeD7@94ZWVmKg_~gos z^`#i`9^mpQ;2RNReJOXGxq64}@sn)OXr_FKIq3y_!&3R>98#|a^@@GEA@65LfnnrH z_5kC#)InFaXnoG`GnR!{fw_1EmE=)QB)S_yppV7?wr>yq12UP(W!X^jGKG^UO@5u`ro`3h$69e6Gm!$eQ}?q0!iP17t(SATI)1?<1&k`Il64Z`F}o zS(piRG+d$m_)`bE97V z_>P>>)|b|Hu3kv%k({AA^Zl+L5MgadUT2*Q|Q0gz5H_<$Bcw7)B{`>H~;p! z_>Wvh)BwhALgogJ21d>%jzV@Ww*Owi0b<%1zzPl!(@KGh7Znz_Vx9%L1%MMrAc251 zIXouV4~sUpA^n!pZVC}Zk)N#2O`8|XHGH&8p!8w~0!sw&5^Ss{Ds@^jBMobvjTfZI zmiJcIk|C9NzED9F1}m(;4lCHpg*@b5Qqng49!C4X+>b%7A~@d%HG!1V|5#)#|F_jDvo zz>HJUzWlz*q^>3gT&vJgH((N;HCH*Fms<@TzdojVK0c=n+A+Q|&>8V}qFy_}rMnKE zp+UHsI2-7qTVQy%k_lc#&K02Zz~4wArUaXb^b0{?gy7n_`c63Jlt4iXMRE=2D%d!`nNn<`@M`b(L zUyf5CPg{yZS)p)RVQU+)Z~MIGuTauE=E_4O&g_=L=IXW$hp0WKZ2g`3ChH_U6E(NV zW`s>xaGbF_%~kR>W%p&%Tebckhp6X_quF*b;NH`CX8ld$QVF`xMJB!ZM2<ePA4;n&NyG04p@1dra+)5PY26B3j_CKLBnYcTZFxH1GD1VXsJ^@NKgw6E2LVX-Jz zFX83$MnUg}O@qF=6-jqYtIo#S2kBZ81PbDWu3TLM^`#7`GhvNzQ+3d@%IRgeU|IW73z|Hx&)lm(si+1@!1P6p z%}zzc#uz0V+s#Bs6b|?zInhYbP=0Zp^|C`#cU&c_2x?kj+sHcltuDMErIF41x34d< z613_5c1zn$*`;5TE;&nfFsr59iu6%9Kp>zg< ze8=S>hVf9lfU{5T*13NRy}tl#<588dqaM=cQQa$vVqwI31h0s7r(`)^(bW$`;&gNG zguO3m+mw6v+x*ZP_X(m%MLkx=zJj{N5kYb{ZE=jc2USMrYM@I0Y$D}#AY z@Z*}d?l2v2hEP9aaDNK4$^l6?ancPU6TuV)jRzf2=;rZ3&lMk}>3?vW$A3!t;u=qG z$L1%&LQi46uO8ib4ZVW-qB7eGyv8=#ej+f!UTX5pDgGg&zNww2D;v|*Uu*;#4+;v{ z#ut0}s~O@TjyCeJn_M_Yqp zTRj>XsTn5wkX6=RT7T@lC-Q>8PwClU-P@nSGv}Zv+=z`Nf@QDQ7&cjWgPp%FTYhgb zO2D44?5*t#jDI(HRmT6`VTx6?ew&;A3ehGl0+^c?4PhbI2?9a4 zpl`2{p;Q|6N^SA`yY5(>qbl(xJt@zX39LrSdgkVIKA7bHqe@!jFX&JZ%Nal zbOgcqOgXTfF;?lqbA$?G#p4tjV__9CX4WJGY_q8|MYU2)%9L%qhty)F{!Kg z7s#dcM#=z$^KGk&;secx{iPJg70P0gYCNJ%c1K%bfaF(a&{Sng`~4(AOI>n}>bjv+ z=#f0Xh7^+y>8w2GQ^stoNeB0vmy|NQ`kzW8&CaT-^H&R-bcHzesP4m)h&ALtA=(84 zc-$*BXF%08WPffTG64kqBND;WD7O|JSOM1Ii5rl#KeT~l+#hT1ApOTc5qEAG?S5{DMDI z5eh>k1l*-DX#t2uQk8C3t%krfUBBCa^2J z3+KYKZd&_Wh+6e7PAAnM5=?6R>@4vhigvN9xJ(L*2gP^gn`l5X1(o?X(=^Bu0~B`@ z5EyJLNYQO_Aph)D24$nBZ>#e3>JvPY5sEjYvI&8hibDm^nHkFJaaxVPMm~4NwQj%j z5gc3)KDmV3EIwh+m72iOFMmbWhC8hhxG-!Temr1mI&)zR=6(HDUOLkVk66%}w_}sB zlpjAVgK|e4U3M^jXF4dMXprC)tLjr^mX;G;_GPhn{tdji{SiUd<%;N5aoso97!e@> zFU}Oo-DXIuRrGP)97Npx$f6V_jtDLm9fH`!k(fT{7+IX^z=|cMDZ!-5bp0W&dG0dQ zytJ*iY(d&wOtA<5UXT)8U!iT4!rwe60B(@!7NL6K4(P&5`U5sp`Gg0{oJHHF=}5Wa z#Ii!>9$z*AS@o`naL+=b*jJFaGxZnNoDQ)fKn~60*AB(mZ6I-U{e`2twuFPPtbMXb?e z2&I^zCNx~&b6VmfKCO>`ZdCYGHm8_ z)BhDs`|t44f8A!R=mEDG{6B9qR{y%q5cBI21A~Ji&Ci!v(~06s;aW`X3vp%pT-F@Z ziJO8OXQcn~1IVba#{1FvFhSn}i@R1_XLz12*Oq?WUFrFLK_8K$^l*?9$@SVC38ZDj z8y~3*5ToR@m&1%zx!0Es;f*hJ=g^G1iG<9NoJj~M3NQgR8KGV`WSyX=Z!x({6ID=e zu9JsPIZOK*kWXcCh^>UoGYwyX#Het)R+7k+(BF`yZKx=F*Q#fallumJ7F`O`%`t(N z{D{;b57yM*5VyUDA>d9LsQty1)hbyZji;rT$6%}xO-@L0=eaF`UR#%vvw!?9=}^le zQ;s8sN;(~IpqVz=?5s0*4e<1I-&kd2+UPz*H{}?06Mjr;$UO)!1g|#gccf+*n?=Qv zWoVpf)u27mgw3V_noyzz$B++lUV{%!`D!(z@8MDPf;$);$uP%>&wi+rFbY)_$Go)4c$-fZV)o3q=p z`Z9+&Kx2UDGE_p%GzW|n(&RC3gCO*N&p6j;Uv_J@O;<(WcwwzbeMaAIv@W8{`{feA zQeJPSV|&$#|6x+3EO~o#PB>s$*<8J>yrc&;d42TJ*bHJOX_ZzpSPtF<-qHf#s0l<$ znmre0+`H#%Hoh-7j@nZ#1M3R*K@Mb-!ZzgB1#y=Xc@_#6Q=o&goS=3=_t=dw?MW8S zp4FE@vrRXbnmNUs-6YoF6}RbwbfcJUIJjoBw)4=#sM)IsNDffuSR9X#z;Mzs+-FnY z2rYasGFiT+rL|J08X98ZP9@Tb@#&3)W}DgiB4L?9Zx)G{4F>iQ0Rc>FLCzMRw`c6iQ4E>=S!M#h4j%A^Y@ ztYS=z-5A*dom#Te#10ze(F*9{ajQdw|Gk%*sePj8cOnGV%ddG7`qwZX%X?sptzX8! z`pJF`iX`Kq26@*dsOwYg*NwZk4c150ObAbiTbn2!qe8JRG-+0lMg(g=+n0ssL%A=_ z~sA6_y%r~&S%yM(rtYq=h4bnS?+4G8eUMd?qHN7y`}4J^Ju&6Y5HI05I|YL z1+AI$j0CR{eYf~04f}SaoYZ6>y`dBbbR7AJ18pLPJ@8;^#JK)_*y%-6JDI{46 zi5=DU7>)7u2B^V>1T(X(>;~$alkT0w%*f~&!>uD^)@IS3eTMNxqODZ4uw@`2=DJhp znzl99Bid|jD)UY`M(V`|A;Jz|e!J5b0bL~>6?< zAj_NpNQQy?@I0tMGL-Hb!jQ(z;KrfQPF1HmGxq@LxGRpQ4toxPjOA^363@Wm)wK&^ z)KOHz5DEA|aF<@qxtUHKW1=1ch}|=#fp86a%C3%yTT*#laZZTJ+*P^}csYU>WzKIq*1%}dc*LJ9Q&Ng^jAo_%J$~sI~;;{)TzL@ z4gAJYBiocQ5;5@`b&=kgxZBqdufoaFq2f<`l(@-l5=k41Z{Bka{DanZ8tk4)|LIE@d7Uz3Gd-^dF{G(OCUN80!TTLS{B0;mSA#n(d^` zlUpWyRf1(X5}Mc6xvXUqZzA!#x;(PA9R>Oc3|d#Mev5s6pOe*Kg3op9-l2Zg7pITV5x$uR03X&UKS<)L`UhzF-UgJ?* zO)11&f9%$*!B3zp=+IM3V^szu;VNmE%L%poW1Jdn`$ZaO&c#avtH(HwZb=cLh$!I$ z`zl=xr~P#Wr{->h^!L8~Iw~V=Jf-jLlCn#6rgJzAT8%&L3p~lFt(bWP6ydD2?Ud`^ zegz8jeHF%+5{av3?2qh-;Jndi2SA6F56Z0?p;%<(d0lo+KuP8b9%o+&8b`fK6e6W9 zmXuTjcZo3B@&b!6jW3lpM5y@W@k+W`x}rmzO_B1QuSok(x@ClQDFIYw8?m5u*o1T8 ztVi79u8|WdwyKi%clN-B-=-1L(ZqqEED6|x&q2duI~x@JP#~3xjmtvfykyy?ilhm@ zF!IqP`4hs*hZ+@61BHQ#FCF{ubNj_$Qd8#J^(a{@U&T0&SC{|G4Ce_=?EH7RIf$y6&!v3d+JGYm4LOSwMpyBok1veTWO}{RFAana{`Ov9-!b2w~59TG%c{579D`=KRr-AyKPrG54 z66o5$kj;V7zp;6^EOk+i5?V!vtk~~)>Dzd|G5^|7z3N~Dgw}2V!Py9g`o7AVju0Y+ zHYR5!tPZ~R?%zDD@@mzv&kb)X_hf1WuY1jxO+Hu=sXIxlTS(@xFglAfn!xval$AGV zC;lc*f&MLEEBjB1^Y0O6Ve$tABIn|4@8T@)XlDe_`u_Q=|M(wPDQo@aQ2h$Bi$q`p z5hs9vSiw9hD1qn_prBDT=hM#GShMf%S04imk=n*DWs%n9!;kdvpw zoSXCkAgLS3xyyEX7jpMs8x0UM+#yJH0+G^EYipfGMy zkses7AYYqZ(B>rQex4fDpA*m*W3(`O)b2p>)LP_s_$Vnl zHkuCk!^26rLA1mi`$zdk34Rn$3noo9|3t3l3{95-2U$CYTeFj(3(1d(^q>Ct8}5$j z@53gFdVRK*CyL>PShm?27}FcD->q0;Th;1gFpVWfqk@ec{D!j7#(_iA>AkQfsY3)rZp&k3vEO$>63b&|8-?B+^vEWF4 z1ejaFo_EnP-=o`BIfBNL<&uqBD{gsfxYibJheh`6GKN9+u{yv~>Su;oZa7Cp8p?KG z%u^a;d0K}#^m8QtP$xa3f{nhD-cUfVQVviBynVYZDgn@onX~2=g%!H zWp>WPCchYiwzo?gX6o;HCl5k8#>L)9UA8|J-QRh;>K5)BpK9bHBt8?H336bKx5-b3 zIuayB3JM|(fQgn2G9bm|$6Ho-hK7VALond$0IF zub)&#eqUdD&X{yynz!C$H<{^oqy~%3!KAVxuSdC2rJOsm1A=6y8D|YzZUL01H=m;% zUe|P{iKdV0pAdN{Xp%bv>F~I{fdbMXH}c@2*R|NV@l3Ih_YmBugm0|}WWcac+!Pl| zKnVV&#onU&{5u*Jxk%{9Zo2CYKte!t;%^1~$~z<$dZ_G#*Ab01kkC+_q!(vEA-!1h z-4yhM*C~y5P*ISbL>C=E4E|3=JY@8w*WHbH;89Rs*8@K?}$NmR zD^KjF$GHrSq?gA-JrgJ@CY+^Tz9)_q%aqCp+^CC14V$aMMHB54F@MEGzInhB3Iu+i z(}kG3)aCdtrooG8;^-_N0t+i_fgOv^EU?cmup&?PIU2D*f%2qKq5qj*c-j?~{CeV5 z_!kHhiyg%*k<*U=4B7NY>s5P43C|Q(v`zH0u&A#}7h8!F+ z&FTme>&rV{9^>QDX-X6kz-`a7Q32f{8&BU`ClBw%NexO2O=&6AZc=X7Of!gQa~cz; zeL!HOs8?GCaSx?Vl~Q+96}Y&N*f=^~bTJGPHvmEmsAhCb${R ztr#R6Y1uG+=vV?9WUXQ2#OJQ&NQ)dlv5gY@P06+#`*$q z=$N8gy*#mu8Hc7DeY~oJv}VsHb*U9&8iX=|STqm3$IJo8p2w+E}NQQs>F3umu^m2uzr5 zbX+j}OMd9Vce-_na!ifaY=8P%i0s+A44ILLvfzb#au6P2aHoW!NfG(hb!tG^R^M}C z25h&b`39qP=XvP3ZJpC{so!lsTL5k{n)&?Z`n=apzAQycK&L!giaEsLvExa(WR?`#o!m( z@@ThNktzf<+SBM((flQ1WGyMdJ{V#WTGmAQ3f6?A_Eph>cJRccwp9tm%Yx*h{vln& zDG@A*;>dU6_DI+SN;DnfC0dVYDS295yC(=sX88s+`TebMM&?8-F_NyX3iIj^&9)RD zh~-^s)je$0eeUHQ$mLy3)*U+Qe!kTJ-??u=wJK#|4f8>@^>AECKBpCgH5zF487?=z zzh8)aFp7<)fakL@JEAV7{x`q<~M}{9}ZKk$4 z<))imPSyg{Y8wExngCQ^Y#V$)8r;04KU}0&E8YHQJ}pRsKobnTkhmc=0y| zv%$Bo#goK?Sl^;J7N%$Bt)A{I%RXC18#Apfz(Y3JN&sU!_hVQf*+edH$d$rqHz-4+H*4Gc|u~4bqAxjC+N{XxYk5-pOW! zis~rFu+FbfHaaw6DNQ71H2a~#Q<1{b?Ha7x@eLt-QG0t+v2uj#to=oJP5(Zkd$nX>pdBD|3#>QLGZqo-{FZ_W6TZbf+#wZBmro$>+`Npffv{j;l|>UfSx~ z>QZv1rl=`!nwJVm0hSdUQ{;;SGE9*QflEzz?2C(B;{No!y`f&}Q2W$`2Es41;ZBIQ ztkJk7S7B$2-B3oK0uk5GD&#^iMPc1Bg6YwhNs6>g`#Izfi!?{^F+?B=r#dUh4J1!T z=lb(YREUu8%i`VLZ|;1_;IQtcPC)|g^5WShCYOpOi7|uF8iiwLmtBdqZ5IQvni9iN zHPf_)zStqrM9m%<#dS0Cgk2j420dA449PhfD5@5x>Nn(oNxn zdpD9KcwQ5OKJLgsU-mr-?&Ov-fZ|1?i8rKH>JEAy6Lm^GrxigQ@wU%>2}|CG({qqp zAB=e0Apnj`8Cg30W;s-@spEX=wk}nQHWnlHTs9kH^@iBfd#6oqKk`$M9UmKl3$mIB zc9cZB6t8nJ}>mkf3@#bRXbTg2>(Kf~zpM9;(& zJE+X=XcijEWe=O=wL^QjHzwY{q4=AH-IC8uQ+<6P#_6X;XmFf*`#@+pZ z@jA`O%tPKwHR@IauXbyln~X@+n&=cZZ;6>bVhJ*=hOn$d<|?Dbq;n|e#k_+lKoEvB zx;%s;Zh9LmE}V_uKA4H7&v~^T+uC=b2kr8obV;^Elzha{S5hsC{DH|I}p07 z6fytIev-IffxRp`9DcM!|ARa|$9kh1DegQ*j!hI0eWd3O45r==bSob&rNpZh96Sr( zdRf%v4#K6Z^E=eoh;Ry_AxY2(r31;{wE4h-ng{d>ZvBKnEYT&BBOopxNYlQ_U z@inDXl*RpEx?AKSA=k+RSdvhyilrQpP}w@1pN2E0??a!#*6DnD(-pJ6u3Pjxj@*+u zdjNc$23y&Kc7-mtJs&rZI(f;)_&(kNt9QlfZ2oROEKVEiI!(kOR2_Brp%jcBM6d}? z?6vy93TMs^77o?3YGBzuxGKv53UNcsK&Mvo$=jq_-d3ghSAX|LDy``#4U)B+HkZ3} z3*}Z5EGVo^N1O#*wb_&g$(S)JTqSzsd`5&(>jer7jnD?fyJ4~sklGjSPqt>TEp9G# z?F7jX+Prc{ zibNLd^eyZUr@bX0$JHH!Qx=W4?HYW3$3eV@7JXnpq{4YItod=}sZM}4VLf(BGk)5* z-@1vcHX1}gM3cd5wtZJ`Q^Yi#>;4^n_B)9EkpXNCnHPFeij`Y#q7;TYZNv$aI_#Vi-=wIHQ<1oo?cx5At(}dBsr3%ETy9`eTBrwfn z{77#Y$eD_XhxwOIt&L+snuw_@t=uw#qU!@D!0a{H&t{+0m0b+<@G$8|IjNzi``rQ2!ZIL5SK)4jud7-RycT>xiSHR4&YW)Ry-J+Pb=;2F(^*od8Ok$Z$ zW6``;SaC>8UWsTkyxc>XmUw4D3&TAW4zW27KHhX844OSM+Sok)F5Iq=hZ6~ZKSmbF z0qr#)G%=ROk*qUvEc;q&h-1C<7~|M=<-Wt}mCW+BRGco%$nSnS5sm>PSb)rdF6R}b zPNobWTUOjalrt3?S?~xbF7kkzoZucQgO>u&!UI~Ypgj5;+hZ)JVCO$L`TUMU+Ft@U$= z>XnF<*a>BMOy~KQv}GQW&F+vh1OsBsfz}o?bT$CD;f%<=1OrucCj`M*7-r%A1;vKW zUiKhIww&7~GHZ^4RxX+Vq#5nBe{8XTOrG6rz<$phBY94GCvo-}$CBFN#d#0zc!FV9 z&{hMb*=eF)zHPwZxo*P{c<0!4M!{` z*#>(n>A2&Q9H#(xH%2)cgmA5rTydz_>!J;L4JP!XWMHDdDh(Z{Z7}u{1Cpb1X)`!` zxsp>>(&i$CNN#*IdOhM(b!Fk`EzevG^j*?3SY!71zLT?L_wX!%v~%{0nf-mg#^5xHM%wphO3} ze1d|qf`byU_Vx=_e+DtDA3k;`Yf~Dl(RlvsljPR7K8*7<)IWV~vjIZu73?= zaQr$xLLl@YpgyO-iSX52L>&6CI;rT&$N(B6M4*rjg{jYoK!~@IGr^!^4XZ3DGxdd7 z)sCCE6fI>~JF#waT5s%H7Fo$u=VSl7={LUOc~JG0r!>?Bx<|!s%E6wc6Ww;8% z^vXWKXc~&VF&LUyX|%jX7(ORxpE5|uC;lb=D96bA0f%xG>6L;R%)+M{xs9t*ZK7(0JsZu{H+x3 zA8mer>J$}SZ2#@E4RFtLcKO${q*z%;X+a*I=R|EDksSD&Jig#HoVCRvPCT=CRU$}Xr<%VrsbwV)Ok8xGw=I!kndLl~*jN+SW=8L0FoE$s{jdEa`|hr%dKP0*5%3 zEXL|8(oHx|M=3OJCxystvI%w0H0JN6Z|SP;$Widtt6P-m>OACZF2_SFlLJp(J^q%Q zM5EQ6sUK0t$0fjSw?er_I?OHu%rI4^GBF%52I{t}S6mpSEK2tll)zYW!{2-0i!_1W z8x=*Bmh1q_b8agi5+IAAV|`*O1(Xf6E}K~#TWHPE?C|w=Xi0{UkPV6KyT)Sf|b1X<-ZWCZWT}-u6ErqiK{9H zjDRJ$RE$GjVd2N3yh2)CHw&Zd@wX5h7X)S1Yk&{cM=CbqI*eihT8CYA$V!mseO!~_ zjbP1q1-Pkb+yymP?NV_qlbH}!A+g8PPD(rmU>2putzTIb>jGaA_?EJNU<6W5RozMK|Rpmdelv-*F zs>oXgwEhHyfPnl5RRsfZY=s%kV`Sk5bx;#>R0WF>Y9n_aqpLj|psrQU;iCEHFPL475V z-F13=u}aq2d=ivSwY)|<5$5k+MPbY+j(9ZF>NAU5J^bTc^pKsZuHQ1d>!>^EpIfez zan_N94BUzLon7Q`n%R#Nt-o3Li6!+n(H#a+y<YqR^9HK4~pavnb06VubT9L`g zra@eJ)0!(5m<}+T=?gju5B5x#bgAFgUoZPxNGAw$t~bVpjDUI$qv8y3h1DMIyu5i| zdaS(!T@72_Eq0JBGtoXSqS$I%E7!i~H>Q=*HMRJkIKVWt5|heI3x7iVm4Eiw19@cp zbm$EK>(hF4jOKKRXu8(PbCui;$=K`N{*V)iI<(q!9 zj?h%Q9j*6cmQ88LEk#i{29f<{i1;rAs1>clK$r3YckMZv9^MY@sIdbl2@C7#Cw=h^1aqg)9==~egkvqj^pb{{qFz@Pd4c zUK(pgA#0;7cJVw+_zSAO1OVc|b%MNg_$zfmvN-HFWls-PRhMX0%Vnyz!=OX!o+gqr z_?ay?$n;^|QC{8A?%yv4cTn=_zI@omLE<57=IGdwH^JJJxu5>T2d2%`>d-KK0l)Au zeiC8>N5lDL;b!#{sj*mcV>a52mmK9QXk8zdVX`1ZdD@JZpaB%<_GWchEEzFfj9(SJ zuD{6%I4XmXdgBf=t>%y;_{F_vSmr1xk-nlWRw-;cDem(raX$jMIVmiBAwZaEome3* z4;VOPb7oOMKed-omEa$pRy&UmP0=lphc;;pya^0yRCG`EH-7ZO69jO}iK6;-E1q(= z+=K~6NL?W3fHnj!z&S$XkrbkWtx%h}Votx7>;Pdt|5z=i>NyNQEsrMr%ySPib{HPmt2~pHM!4fPFGmdK)C_HA{|;ya3~gbf5UPS z_UMo&iFalmS`{)yb}-q$b+tfWSTVbm!uXQ$O_eC;chtWLbvO+46d(6t=DCqkOe+E7#(3%B69kl(`G53Umlv}huY8?8eEu!O{y(~P{h!;l ze=HxHs#?xO*&{^DrV>eqcBpMl#w0fWuc(xhYV3nh*(-{9Ad&hwqR zd>-8%O+IdN_&$O{;pV)cTxO-9T$ETM(#HFY6pS2#231hYsh8BXjc#O6x8qMtct31{ zbiZgo_c}qkh0Dloveo1FJVC7UPbM$^!mW_&tYyX2n=Y_wgnx`D8z@Cp01am+y0B94 zGPEaZ_kxp5m3CmjM%CKSC5vz{Qb?4M*8{<}Y$xe+m`aR*77)gSQ z_MHLEO@=K&^TB3`op&tjJa#Qq(HEE^22Rc}&*4gUs+L>Su9Ej}?~L?F0Z>F1+o8gq z75-dS2}Ng(#xoV@O=eRWq6d){V2AqQQKRF*XQ$Bi#oeteQq5>kBGr~_(0lT8EY-UM z*SzygK9&qGymQQP_pQJgDwYdmXr&mBkNZ8Ffr**M1 zg54in4GoCmHSc?Sf3qXr?T!Wg>`Q1{kf=HUTJx z-MCxHs#=OrI@{LfwjHPPO-6eAWZ&6o5HGFc7jUU`Fo;67k(AAzQwGI=Xzx8SC2a!%nI`ahS%Bi z^7PpsBB+HO8A`ZO+ZHqUJz`kn+|1$Upa5!!I`&`750ZP~A_6wYMv;tiJV2>D8McZ( z^ztF&vCa8x zJ;!{N@UARYmA@Ss^dg-6Fe`F82WC+x_145}iumL#Dyo)-wOMU~2wub{^|QlGyRaV7MQl7!+V1FB?A|DCYjjrbxOm451g_4CufNz*%Yb;k9TCU; zC`=?tVB@J`no@ZoSY(&6%sT!I$uCzsoZ^sNtv_d%f3*~|SGRxyitW0tirnb%EnT>M zA5&O+(5tTU1+(CJ=4dxev?QV}Ogs-ank)Wze1`KF;aCgvUM$bfW~NzSdn@ob?bQZGA=?=;%`Z7h2jE5kYwJlH;OB-GEx}8k-sNn8^J+IDG?)FXB3o{vW%EV_xu$NwXowmRqM^+-@-FtC0*k&^ zrfdUg7S8~fEdX_$(4JdD6Ytnv9WfKH-x@Y@tLH)*gz;u6-ve~}v$>dc;VnAgFrOfp z#};nrJXNlrxpls8ROJyf%9yp+`xRX(26WOT$Dg~_5}yj!CYp*xkfiZYCo`UF)-Ftz zYeaTb=>LA0+AD52G5yWryLydj_A5ie839Zzoco}70m)}UKad(q5iAgkG_r7+qIpUnsj9)OU#c7T4s zlS7k^8W~d^59Q&P9S7oBfq;nP$dFA%M8M_Y;^+*k2XylbUI0hnb5}fe4QTj^m><6S z=&5@9je@0jK$V>D)|cPOYt=WufpJ#oJV+IiHH}mdSbBpe3AbGNfTmKjF9|WFGKi?$ zf~&FMSJ}^y_q4Y+IAMu^D(LE0P~jS+Y5Qmmy!&VO!}^;bte;X$#4)D1s7)?PD^A=H z%qED&>)%MD^urF0uCJl^_edj=|75WKsZRc1oQMBzSNpn<`K$n91ysB2$T zf9=1K!t=!O`ApBp)w5DJ3jN(mWvgv=tg*4z{twf}97Ba- zI)Uo%_~}*IG^yYT!(Q66%g3!?3%*6EK18^bzl+riZ@1 zQpm=h@$|GbYM~+;73fuQY=aFZtMODvza0kFr@-9`?X#0)d?L`Abk^to)W-Ry49zd; z%8J(!w2TBAU^vF-k#IEh&7{{x2r95q$5kfY^?CG+MuZpY>>NV5!LU4%X&n>^*fyqx ze;HW%f9Tba2V#6#TEcsrXRhI1LWOHw`fJBw_=tZQ7KTjui>xGPSpM4g*N~T&izg-X z2-|yNU-driU1jY_7%s0)fgc|Iv2|b?T{Lc3W-y(TNMjmUUq z-|uLpuftWYXr{yiS+o4bG@eA%P|tcO3}piA#X%&+sz0 z(Rx%W4_e3?yy2~)cg_i2$GNnP?-{&7-HP7F^2Qp*LJ!+#=!)2v+0buMM>+R*983cF z?SxMUPA!QGd*BL*H~GRlGz+T`SfbhERcZEe^soFb;RGX+v-RP+fU9j>v>|a9OA28 zz*+#63`$r)Ic6mRcl?A?{YeX667_SJry7<5C2tl#%G8`Czlq8vQ2rD}b18bp^XIjb z-2ue?IwT2?Ny8WI+LEt8p`#5PkD$;Pvj2HySPP&+VCkjQ9}y532&LR``Bb=69y@hv zOZ1Q!j1UI@=@Tz#Ql8gRqf5P+?Rz50bb@s8xLvRpJOT-Xi(=InVG4|P2GI*MsN(V{ zbQdEQ#P`2vwW<(QJfkneTK2z19Q;SK+J9FSMQoidoGnb8{yUbXF=gB7D>ZYto6V-p z1~XR~^bY}~#9}Nk5DLPt!CNWG@#><606zN++j*Pjc82!6sDAe7{QXG2YX!XfuUF7i zVqzSI_Y9dB-hD6M@J;5X4Pu>!xsdlr=h0T@Q|2AV)0UH+@8{Fe>o>T3;?uRbPTP6~w7V(ADQcBbm)H3ynMh8rY z%9m+L^kf1^-!+Fa0npYMX-Re?rGP@q(g+VJ7H179XlIj!Oj@nM0K!;v`roPZ#iO3I zNwrXA*;4Q`4Lh(JRC9^4lOto?iaWyns~SeUCR0g8EJg%LO3sD&T4Ty(xv8pSlm{qG zEPIsnHk||_&C2D>qB)>_vP20i<{dpX-CnNS9vs^}>*?7_q7I5mBXC-4gmN;a(eYAX zMAgXDNm16G@&vHl9k@tnWM)YfCRi)Hn#4~>Ne+w3qvyF*Sjj?^_A}Ar4c3~H1`fJX zlVhtK^D|10Ci17)jSvrtqP6BQrDyC#r)4boGs!Dlv@^bQsfsH)Dr&UIM`THTsnV*T zo*cPrE!y&}7p_fOOq6L!vdAhnk`(ghA-dh3tn z=bgE_3(N^f14KtUJ8>OYjQv6>pjE^jFqQbn4`nFN1r9%!lL9n%Gi!s1qwkfZz&x;u;If^D<>$3q8~B zWEC&Es9rK{sgG^$F_8?2XXyms`}uhzvsO?<10%@M7-;uaNNQT!#>`Bdf>k*q&91G{ zuQ=wT0~Pcs`r=0w6GsD5tVM=Uhvvt01pM=bipEPtgo zh^?nd7QbU7Hlg@;D%%y{a*{5riB%%5i3973SK-HYL^N@kyOrfCxv(ewR?ZsrI&NzV zn89(TTOE5+!Vn@$$^qb9 zJKJ1sJ+FoHP-T$}w@<=I``n@gvl2F5g``-QlixG8Zhb(|{%Qq!BNN3~3Xpb8xjKL% zdOEM79#QZD@+^IaqN|j^n}>?tRat-giS-Mq>W_TgCv8)e=Z}(`9j)*?Hx}GLO58y4 zX$LH_Idrn)-apy)zSq5B?)HT6{b9-ugk9_c@KZ5?cM0&a1A}3#Lnqfe8>E>ec$p;- zWRfA~C`XN+ndT^D;R1M>aPV+haEU(l0OlMA!zc%0_$i;hKZ6ithrMAu)-JND4u)Oj zL>~6OB$?aZ_J)_I16cdcp7tO3nS4I>d$^hGIGZY&N)PPCyL1obYy7fDRhb|JEdO@(soitZyDPLp|Z<{ z>ie^=yARR-_`KnrZ3Yr6y2?g(nT2dqRdrjyPI7pgh!0&yp%&Ox)sc*GdsZXdmRf~Xsy z$pxV({?4(7I^u}n3YDHAj@b#3Q7EP-4|5=1Rh%I#w2Utt#_m3di2ebN92gv7Uem4Y-m_2YHx$oA>O%go`z@1~P(C(5u zs3tzZ*{CZ3>++vwpf5=_NY@oTNJ+5Y-DUOVS6zXoq0i-;lzO0nW{@&7eui*lXZ(^4k{yoH)7&q}d_S`X??eQj+rjc^^-Q%&Jj^-~VaS7-GO)SL9$ z+l21Nb!(3uxmO20lnN#b5f_G zepk;GxmQvTu)i9WR}?>ieRJJ16gBd*j!8FJjrfksn6I9GZ4Vx~S0}&F4t&ykTo0l@ z8~Lk|e<83R;5-U=9P~qZH3yOz>{8+J2zVUqLvS?%RMNj&`SHuG1KFXmss$R2W=_$r zrXSR!mDDMtU)Zyr)G4H&)Wen3DYXOY|C-pTrQg`&mDs7KAJy~qo8FGFKRo%Xm45;# zZ^^kGs4VKUmI)pryU5N};(KRLDKMVuBRp_1H|{@6$Bx6c55 zH&)Ld$uESXc`x@%Sw1(vA74Jq3Dcp>0G$t|=A247s~p%e%WT9-Lc7vZ?42xYXOqGq zON8hdS(RFXvMJ-+vun}v=TPn&TaU5h81_WU(Rr~)zgg{iRxcl#=fbO|WI;pLS7o77 z$RRzn)_MG8i(@!9KPJByUjA&JNBaJ!gI3N;9`>$*y|XKJ{sPWDKp^mzG-iHzOSqON zZz(!?GW(lgT=T`qx81w;d(UW9vj`}GeQu!Y@e}AqkIsfaO{9KjajTE|@)wmv{2An@ z_skwTylZF&1`YC=Mg+^ssl z**rBj%jBLjE2D6phq!+;zj$ApqG@LkMe(>klFRoWQ z+^S<|ZSOdH_;lQP`}M3J7y6snOzGE5;;}2@=4r~_mX8yzr?&-g&#!LbUfW*EYgL=y zDMe~qfh5h8ryv8x#2DVLHhHP2h=|P~ji9u&tY1BH>g44%$Gt?bzP|aom2{RzwL$58 zsJ6wmhS_$vslmDB=Et#~*w|dkA5dW_eM8F;j-yOu6JN(ChkfQ+>#U5*r%0vs`{}6Y zwsJBi!ish5tf`|5HMf_it^FMgd2(|XkP*9#n|oIb+s*~Y2d6Te&5I+`vu~jmQxp@f zhkl>AvAZyM&&=$ujEz#8rn9Q>poX?|>FRng)z}%vcz(;isIq|?ZI-WWzOC=B)xwJ_ zd%q09RH_ch$=(mpxIcGsC+{^W_Rd2S;1!c2sz_CP9VBGe9@SmbO`}T=Z88n<1e8A7 z%Vlapu{U(X=Q(VBZhKvzX-dDu$Juu+ehVn;GlfZF{i z*+YVPW_t_K73SF;SdwQ)lu+!2aTjbv5mTJqQYS@*EcS$TS7cF%wty0GgBe!TCI`t@ z?0g()vH|C=tjJGkGVWm-OCiS#Cn=e7{)BN)9)2YCf^nB!o!e5j)?!8pA10g?PB-P5 zt_KM1s&gY>UKDoBfp_F$jza);-A#Wc#{?sK*TcFixF8P($H4eVG={Qoj&B_527jX4 z$NritFsBqnV`avUz_^Aw;^mH&#twU;w4=)^3ahT2EHa<3zN1_RfYgd-#^(ie^g4x< z;8JP_;&Om&{cbBA$2*0FAKc@Db&nu(RN^a?P}n{!aH$ka@eyl06tMtZ{M4Dsjj0Mu zH}CNZzdI@MTAX=u`ZGH?US<>skDL*5$D^QyG-kE<7n3O2t>h8uLf?LT^Wj}TVtXUh@MOF{%b@P@kdty|zRzTKxvh?7K z5%XYPi8XtsEIgS~e$X&?RgvYEY#}|pUM)86O4_0ME=;GiXI&x#YDsqZE-~1&%fl?> z;C(P?h=j;~L+YO3SMJXE@E6W_{LVY9&c)hc_`jkdAg^lngSR%GwmN>OcdvUUZ zw`!>|tI*ZhtYzd8*AI!J64BFISTV;4HG40-%|u~hQU4Hta&oADQd#HE| z1v5owCD_a!izm|uDd2JxH5@Owlk@_BLb_JJoEE#Rn?B)DcJ$@QS7;tbm{a8AgUBLf z0z4h(2z!tc?hNwc z8Zo=`1EX%SD)!CH#^Kj=T%4ps72GQ-_4QT@2KF7j`<#m+nZ;8Z82*>QC9+1|!Uv1W z=`YUlnUiMD@=L%HT4PtigGnVsV;A5-rLx+>N9PPnb9><>d8xUvEB`^K^2)+T?+ikd zZ{a0wNl24#=_PDQuF<#X;V!eR8JNnl(W24H#e8x;y}FUVd`7dRQQWHb3lko;q*!U9 zDN}i%S-9k&Ic!xqqgmQ0c?Md!sA<(8yTB=NW?ZS%AiKyZbLL#hlo+6_=k%>!^qn7n z>X%?<#ND^rWOH!&)nmOlFn6vM+;6Xw!l5qrY&ox>Q8_Wt_s=H!`%8o;CGAMJxZgrB z?Xb9T(dP7s*r3o#8%uM1MQ8L-@*vNhQ!Iox-z41leK-5ob9a(w(F+%#?NJ8XFvE8- zqg5oV=G?U>{*V_l*6kx^Hzv9^!K9oWKQvTna#UZclC!&7Ek~_t>e6CYjXdm0ZoN=y zXGt~abD>DOux!cjofOuL_i^Q#(;+iq!fEuWkEth<$qYG)rqK;EM4MHR$0kLpL?Q)N zm{u5Mnjel!OeCZgr-C_B-Z3AZ6vZ;7nlVl@LLXQka!fc)5^}_}Cbv#eC*P%^(bF-* zwuZK5{{gKRrZv^=>sX*p8c$7Os-_?REqSOiQ7)rYWuQCWF-4tnmc~YJ$6UBEaBjS1 z9i2dH%2q#&O^220lw{3FRglt}<`JPm;WI%qQE8fV&(zG2V=fyDbcpZNu0g|<%9SR^ zX!Uz^LT6(0P}l?Nu5_X}E#Y@cs?dZUE7>@`6TH(vCZSha{)Eq=^6E5q4>nWrsK8<6 zgo9HXwxKLN*(8Qz>L2IBL=L5*G^Pm+r{s;Hjx3K54y{XLTm#BH?$<;&1KY?pBj3Oqms9>5&t3n7A3fXX z`$P===dAM>9|Pamo0(Jn8}yyggddB}t=&Wn)90r1_!sdf;g6qm%$wdJ$X7?ef?;zm z`^rI0F7rx~nSe(P)po#5Zxt|fS%6MoK)Qa4giL}&i47(s%M>w1gFYN&XPcEoIE^~L zp}M@BqG2y$ydrdRLZU`Z_&|d`jYKOLmUsb}Y`g<%i^P!DjJTqK0Fy)^7!9!sYD1iK z4ZgUdjR2WM6qpV%5)FHjaXc77{3z;utaL5DB;#TLP`m}IHA$MSK!9;DSaHHc1HKUB zc)$g5Jqj|ryb0=tc-=+-4>1*WOPFyX7+XR`oj%>DCA2M>hEcB$ zu@y~Ah;bI!Q$j`ajzBytDz|XmY(R(vtH$;Bu=xNn30AFZ^sw=OVTldYw}b(sUjH54 z9xXUOm6P&K@va|Z$FHnllKKR#F7j|%`q<7wU@(Fxk^C&@0bw;*r2V+5P_O!&=OJnK z-%RJL>ss%}OOk!FCW`gGLsOXYRQV6Cz)00%CGX=`3?QgSwd>Pd20yewu!|I8e{p>uG6v)Het!uU--w`;04;e z5*TuQQ&<-`ZpH~n?fl-fW~D!(3nB4}$-cP-W8uYSeDSMhlNXrlqJ0PE)s}s}3u3D7 z>X*~`>#p`I5c{<6584{M0B9T$`?!2?T8D++!e|!zw0w*zd*}IT*o=>=>fXkRvyZGfYQ7?1xWi|t?8$^SSU{{?~h>ihl>oM)xkMa=~U zxC_{flK^(2!u5d=$|uk-dXCwh%;lu;Wm1Vnp4AkUv2k#+-xZ?01Vez%f5A`oufErL zb-lYzOZa~N`GD?0J~WDDKp4i^h%&?vA7y8j4m-#W-B6pU+!4s!2m$6(oGI7WY{3A7 z1d9pcLK;MZ%&Uk?smY{bN7-CoqtciX>zuH;WXwTxN%88sys~kU(_^OLo%Uv(o+NDc zsc$f|ZqG#Ngq`w1Pl+g_woG;wV2 zOZ(*NU#Hh$RTLmDzmRavm}W^?o9Pn1AT2i4@Tc6;B&*$SrA@>RATXE|9|%9{$0fs} z^efp3YGRCO8M*N6!6ZXvM40ibxs(Yp9#)y#4nJ~A_mNE+Q)PmFob|4pcJ`k2)L#*0 zn?n@QGrm-mZ0)m6a*ygOqU)>QyWVEl?5k;3*?>7!FwBG3&5bI#YZOW=+vx0^SVE69 z6D@(5l0>QIbTcp>@banzhIVdAGT%`;CEwYytGo$}rX_yncZrP_uY4a-ZO=bQeMn5r zB9$CYz^&qdqk)1pBj!Zz&IJr#ek=;Vt23@NOQoH*p@Ras+nkey`(G=>WoUGjL2vNSWYwPYA$k>a@^}rhBLf@ZLKnxsl zVd%7mKM-jV+C){kZ!in0%{c^*kq97DETTXef^I|X3$yvcl6P#h6Xv&n@CH!dYEAvt zD^%f`BK+vWm;F_sLQhQ~oK8W+!{{C=?s*OkcqPNWKn80Il@g+IA#OoLMv7z$@C_v6 zgxWQ&IYU*EBvdh5h723qy*Cq{mOA4iq0uguTFxi(zgLJ{#M%VF+;G1FdB`XUYM%eN z0cil2Pik!X)&x;QRN(?%Lv@>AUlOcpBvX~QsSdq7V}i}U#+O!x>Wn7@@!*DGqbyGl zH{2PS;A>#_3HH}@{Fmz%IYK7Z-O8(TBbNB822CIji6e*S=@e9Sq&gj4`4ZtBXL`R7egW^Pv zB(dP2y*2_%4DX8U%d@#+Jt9f{X-)1Sf{Ypy zQeqjXEsn(T#9=y)<&$L8!g`1G%U6ZDVmI6RQ^Ew>l+g3-Y*pEuWK68w>WG;YOT19^ znaoN86rq9_?U6>qPp_ttGo375^MY)$3IaysweDbOAH~sMwk!Ju6T@k5PE3@!AsA>H zq*KFnk(D6Jkye|jFYr#RopCspNXz7WTQ%(g4q1^q^6h>+%vO8FT(8MpjCUA$9+HA zgzDYnA!57oF3{tq1Bvfv(4mc>4xRwjaeTo|*EWg?ciRX&!PK|wQwMs*3YBKN!6h;d zrJ7eeDUi2>NHH*e5uz~bT2`h63!^J9Xp)D!Q>gx85szp(CFTh1 zH3&8(RbA7Y$=Sgxq2vB%_*5fbS@||E(||F08@(l-qv>OsPgiHR57+e*U-yTAu-V9> zL_VGK+=(mMR(OZ>onuG}MpTz^P_=VD5a&QI#IGc{G%KQts_* zhY2QH=yF2r?eu!!n$oszZYqm&n2-l3HaFiY)D~Sc~ zi2knn(Ki_<$Z#`FH^aV_1|}8FA0~R3;!&E>2Qd`Nq2oj1SYGFHpOJ#6fm#UXWe1^x zKDES_^QK```A5N8tQQ#drnT6%Wgi`2hDYmB1Z3qXXk$Q4j@IKrk5yEsex>P6l>SUh zIw+MTp%zViT`^9zc&sN|6BnEtddN)4W&}k0(fco?Is8MgqkdEO-U?oI=2+0Cf8vff zgIDDltAyan{V>c&hl_NMAdy_y(4h-uxV_4M5g;{gGGmop&G;{!#3F7l$zTbbPufmc zeCh;_Jsf$kKUu#;hUwfRSS5G^?#*9<& z}-6fz75pw1#VD0FmRKr9Lb17F5084TRznEJ*~zBaX8GU0N-%1>#|s zkm(<(Xgva9&ZVkMvm~_Q@wIeJ`?Rv0jvS~_#BtS1TH5L-#kWSbNtU8Lr{}_}hbXGY z^n~OuNDP}p;Di*$=o3kW+?cTQ1K{(7ZfUL)w^xSY{tRuA{Kk46R2Syp26^8K{>TpY zEz0xz<_Q#IG{XhA4msNQbKoexHHYFxo3f^#qSZqDXwF~oSo>Rip)Ysyz7$+{2gK`$ z6m=P<2v0M`DL--}d`z$Uf-&+#->_Uf|3a5_I2!j&6oTvRkCRs-Hr(4`hlBe}8 zr=W7SskoqYT3n`rIlfftVVu02YR**8z9X(f$T?gV#9RF(dB&5jZr$wI8YW6Pap*zD zA~S(m{mh8MXetQC_d5oR1Ki#7yI_{w$@gL0c*;WEXpDk_L_ngaF$xO536zQpG%ad+ z2`ozqtp8eEtY$nXI7vMMCM-@XIJ)bb{;AuX8Pd6|gQ^K%cs--VU`m4zN#C<9(*CbJ zk|5r~+8_5SExL-Fm{sizyQji5+A#2V$*?~=w@a*4HS%$$NnWUazHVB(a4YA4e0M9$ z9?wA^DX}W(2t_|n03Qaf6xDWaLw+omMKb6S{X+Cr5sFKk`;t14naFaC zEw?g*Z3^!chtiQ4=V?9K2DsLRUD_-J#jgite_*qC?HeBc-K5xjTn=XZbt8HBZy}vD z|H-aMl|jhB(fA+J_l4TJ(}pU>=cw0gm1`EeZHI_;2D6N~_3G46Yq4zB$`lw|v`$-< z0anjQ`>p1vrXz`sVTe>7EVAeBB`@Irrab7{OOu@g`yl z=xMuP!6ENcf2I!HrrbEX?H*G6-X7t<$?iZvwbcT0Ayl(HStC?XtLyC5Td28FZBW@X zHVkV?jk21zRj*CFMTXQ+ykV;;o;kY+_Fcf_c3?5wh>?q_$L&eA+RiYmKs^99O_;$% z1dZmJh^}&a%XX(pO=eA$_2ts)%tq&@gG>&eHPmx6zGm(9kja}B) zAG)eVF3au4%~{Z<^Y(yX7yGn`Z<4L=4T_ zjEwE>nmks~jA4GW{9)s^kyw19t(aTsP>f@_K+LyDId%A}d9xNUh|Hla61C zWrT{BVYShhvNj}GIUcCg zc^A2>qm}1MFfHbJvPCdvGKPP^w8PIS1_im7-d=$OKcDNgWwh@107iAKE2k7 zgD(S=d&YJKVZmsaz0crl;Jts$MRQG})Yd&CnxFVEd;Qf$M4Fl>7PelGnGMuW7T}I4uhaJYw7{J5w`+;7XvLI9R>c?apGZ5kdlft>eB zKl~{$udP2Fm8n^&S3FHPtsL_4anIx?oFD=yC0{=uyX7$u*Leut0ah2^BM?xMktEbN?#N*udP%WoQWqChc$RO{i<)>x z0OOb=%Gz2z`NJZ&%}$(8^gRnd>`i0_&JO1?JIfV!t45J;fc3MKkT*@N!?4s{C{ykI zc+u$47$D0;ixgez7tqaUPPDsAV zBHZd*XWXLL)A3G8_09;cf!xmjL=ICD7qZl-A0`|8IaqksWCUt;B7u;GsJn&2Y($ITg%?S5!7j>~nR*v+#NL3jtslsX>3Mu7 zBtUnBKFmdlAeBnUtH=4;UP2Wl51|+^(&x=5(oJTNe~Ki zG@m>?riNLTFh*&`fBt^fIoS3ddzD3!jUz&UTkZohf7NM$OOCVVbQ@R*9b9<&iSTK~ zPX{oZEft3QN=@T=UKx2@n^On)n&w4fd=ij&9wl|}SMZ?Vl>EXpKPw#FRXMoJv9nd+ zrYS?rlKSh%b~O&Jzy7==z}f%g6Ewvxm|VPaC%DhVv{oJWB2KLjVLG^DvYQC##QL=FND0VS@E3r-7}F(Q*<3U(x7IK`%fs48KAu4HVN_;l#nk|6Taj8O$T zMIn_~;`}8G$nNIOwVl_If-Be$$W6D|a@Y@qP57F9+TZsO;>DLip!uN(S2GD-YMC0h z%^?G|XgNd3{@wVO$?>mKca7EhoI{a@3z2xdOOfS$FuE*6&SgjbV1BUFE&W&SvA*5C zQ|&E-S21690cl^h0+T@3sJpC&ikT|M?08b>3+y8_3y!=fd)?S%v^C#oGK=t;7k0P; zlt5IM1k%(CvESKvND%LVefBB0m&MMnIlFhy998>h>iu*#;FYV+`&lzlZX;3s{#Yi? z?>N=ae7@jxV5ZGsh^sPcp10j%ax{ZWYE~Ak?V3p33Y8|SGnO)@(B+NT8LE{J*XG%p zxT+-wH-ZmF=WS?VLta_{2a=YwK+3}aD(m1|qkB;y4?faFk1q{c|BhGSlKGK~TOk2g z|49tk2Ps$R;O$3TM)#YLq(PN6iH*Ivx=c9+OZk|k>}2^Ei1-sxNXo!&^E*zSoYb?n z{Jdld7)xcKT0pvLUt?}j61kwS4Am~Qz}H*E*Bb)M%h#uLU;hHCv%q{wGnYa6!%%2r z^oPgztj^w%Sx>>tcJAf4OM`jl9aj)P+Pq2%!Xcd7y#l7Q`2W{&*W>?Gi~c7=rSe}4m5_j|V^!3aS}d3Tz7kL&V*cOIP}-z}X-f@Y z{d~_Nv~S<|##RIn0nltSB6fDut<6V|-oBk*>B@Z$p_@NmVFdKl+qz&JdgRNX$uQT5 z`yMhwL-SUY!zX;GD@exq7njtfza-gk_i2n$z?z3uE|P7IS-yJrZ78=MJEo)1k^`F; z!8jIUQG-j?@7TnIe2wM&58}*)vfHCYOrZmdJqt*dMP<#^m{O`p@sYSz70J&;4-PXL z8$w>vWi~;|@j=AjHWzCN?2nUmMEMCnLSS|`g@=R~VeA%FRH_XwgD~kBw&#(UauctL zU%Jl;UGN7G`uE3x50~gFXy3-hq;k048DO!6%qDr6xGPQ|Fl<%Nk?HA;W2>Z-4M6gy zo4rws_~EWoJgkf9T@Sq={bP!=(?u{c1mM8%BG_-<7#{;R*#3H&H{eE6a$ir=>I;ti zuXeLHm>cb{2l!uK>|Z|_+1b!JS$UX#MZVIRnb`i7AZ}tz_oePR(>Z(Cn>f)4+1WaO z<%0+q{Y6**7gs$?$wqEo9@)3e#i}_82y7_gIk;rqy%ZlQNkToDAQfz34{;AdNir>{ zip3`6y4tt|J!)wBgM7cWkf7r{;w;3;^U~+?j{E5TaeDiz`x|mi>bIB^Vr1?g^yK=a zVYU->*RdB9VaF1Rv^9Hi-_s5}5PYclP_F}p%9Lr0O!<*e&j5zR; z+6=I&4zbq5t=zlz@Oxi$L8 z)H1hMm3&bhT!5kW8xxGtErV2#9QRRI=ZjIbC!OU!N6SWWeT|dXi#Ltv2mjeM#sA^ceT;`5s-nxXjch zYV%Lr!>SETv9|%Im>C!fVIrGQ?O~>AFSi`M;hWaTTxr{c3}hYhS@RIIOoQ$uZiin~LiT2Rb#P>!&J2#VOe(6FoLi-#a#CEM9Zn|zdTJPU_FE_iw zZj#{z-RTusTVyxSTpE7y$(_<%p9s{n((^u>GCtl`=IHCe<&*n2h8b0iagQ+!Kn%pc zQqBzQ(eo@L8NK3Z?DY`-L>-frv1{j}!#@i5#q4>8<_Hn1%Zzz{U>SDzGI{?7{s0#_ zK@Q50&UmzNMaJld0{l+<@h5B+Y2Z#t4<9?rp}+#|Ha^F3H4$D9XYOXJO1%R?mg#rpZ>bX*dt?)?Dfxn_ZoA} z`OF7))sJRZq{5e9?|PEf&O|k_NS(=}Bu3*cD2lS|6{+b@N(*Es#1Dvw3+uHfB04H` z*rk!TD>+!W;OfQ^bxoMC;tbqtrfa;uy5&&aGL3)ct@9nihU|ZYm9(OKeZ;gyCp5f; zDlV@1Jyy;VN2XiL`bscI_d2C`W z^9T)0fWX@rMwJqXtm>oP??0?ohnDp1FAP^G$i7tdvmAQ;OF8`apY?CCZ_4D~Uz6|RX9iGZoVds`#|N{v@+^!3yH zvougYgtL`?`yUKKR6+MjQI#DqdW^_P9d2YB;0=Ez#i^t4e0_Az@w&R4Z#MgQJwDzJ zD^1NVEKM<0RF-=>pYiIM6t*>OeF?$QDdNmlkx+;alDebR%pF9<`ZWD>jCf2en~M-y zD>Vt9i!0-fu}4*`Nr7vikb*8+dZ<4Itc~|6o?NdabX6aZRT~_Usp|AMIXB4VwRP0# zpW3#PpfV8^-$M)y!46*%P_IyPnt2#)H4+@6gYukLQyfY4IXGPnmD@Yc?UJ-L-!H24 zYo?XgV!8}UZGZXQBdcD$Yb&FEG?dMWU)BQ2VSA0c{bMQQqW;h^`=ZnNV@$zM#71Gl zN!1js4e!)@c`AfgApDy;Jvto1sq3gN8tJmW0WPF_AC=67kIz8t>Oxhp_7*MB4|)bB z#%2=e>_Fpg1FS1QA*V})a!+xii8>>xyyrL_RGIDC0e24*KoZ#lCkk=2k*gqk$$dg^ z6F;UK1{|o@w#CBVsbt)0Ye zY;@vXD-{uGU4h= z>hWf{1?PCy#N5KOXXJTYYVKKWMmfy=;h@u!*8g=}fZQgSu2D@PmlN$rWLv|@CS=`X zi~?*+lQ;^-wkwU`?KM~PyXZX@*~Oa8_YXm^!k>??T@?X3%`}#*vD1$8larjbQ%>{! zvh;fQi#vOW2bYdzgw(2wv z7dwk@BhQ6GKHRyeE^0ZKwqS9Tq$WrIvGDw9wIj8A)4JRxXiHR?A(o$w@|A zzFY*fvn|#xF*OT`BGzcS`I2W#xEz6GDQwOlGmQcl&%&9*awGl6*qc%1U@>JO(w}9f z5QjIx_Bh)-s1(Znf>?ABYMBUp+e^$ytjI38=lmxa7YWzLOfCw*x>>~MfsC<`0P)4m zQbotIi2B2vnW;_V@V1-&8vJfll!cLcB3yoT)&7Eprr&$bNAz+A3@+eLCUD^E_4(WhG_)CIxjCf3<#0Q8S*C z@)^Ocwiu-?X45fP1G)DQ!L;Ovs&R$gkAMv{gOkEZUX0z*;tv2)6+{2vS2&||xr^zG zkUmHK30fJ{n86WPn=l6ru|mVj9eC_h>*3ew6Q*wp+zYQ9fG1E}@~)4fJWp?gSB#Xi z#$h~}*I3rA`0gA9byTuHLBmfw7@q@RN_~@_%MMmlfGo_PbSs@sxRhx5aO)QB^sBF___3o`*B{i;|R7>*Dpib$`z{6#G!u^@9gI0arij207;a{)P zKnLvQ)h5vR;=vV`qDEB@_G8z}WtW-~I0VL~wxR>z&rHsXRMWp%uA|uHT=Bv-{d(n3 zQ4zOutJ<$pPu65Y=!RFf)0VxL5vN|i45O8*0oQ^`^fxvFj@4j}pr zyHqa?M#aGcd0#oL+#z~;CS(_$3rIxVN5VWz`80mR4$Qd(BIBPWa9dOQJ?^IU+VnWJuG0uXM#?PGqFm) zOHsP`-rgh7fOehn<=ZjyM)+{t&w?)4$tl=vGxzSbt;JZ_=K9Vrhj5h)6OXqFF>=Qb zM2YTvq6eMPA@Y}YS*(JGA z8m^J(aNN!F!c<@|7$z7TH@ZmiFXoYLcR{opYnPy3*7~?4BG|WlGcs%wcL6_T$$DLF z@f(vK6zw%%KJDaWk4NVC*BaM3rz4sy&AHHQp=m zfV$ApE`E!%uZJ3wUdT`GgeyWBGrJG@y`d8EfQpYab`d*f+FsNOPVL47R0k3TgsF9O z8PhvDPtVDB$lmnX5=3|f)?i384=L)~EA&3-KqES(I9v-B5O%9%RuQ;#lmF$6@6tXS z12H&r{;fC4aRqOILvI%xOyMPs1`3elXUq-!ve4`K!TfzJktZ|z3%F@B?6+aU>_!v) zA*{3@qnr@|ui`z};?q;`u2`znlJt|b_~wy|16|~KY0L}AC5LzLK0ik-7%@%b{@kl6 z5rGEhy}FQM=I-|0=Kq3@DH29> z4|TJ(MKzdHWZKt~r|g;Tm|k~dqFbW6NoSCib)bVRhEve!QbgIcLSTdbm8>$U6Vk2P z$%Y_bzd!jtGdv;-qpPbPrRD>09JIRxI;|;vyn>WKCS`5`UB{iN?$LJ}9b^nF1T$?3 zL8y)A4SJP}V@mIg%d!BOu*Lu9tOy^lRN6mJg5P*oUHc?0-{#B9oXAaS>>gn(*^*`9Cf^c4b+!VM>w>4$E*{BX5RnoV zaD#a_T*tIUr!uHdIZ)8F$TuzrRNvY{pz_)mvcFSV&}s?2&BBnn&@HVeD2XHbYVHF; zvU-_NtW6y4jsD@A z`#;VF9!L-|SnmZVWPk>@r%#jE0a%b`pbtuu+DPm?GN($mrT8Qa>e;d7L~*c z?bdSH*cp)ohcS1jih9v;-HgJ0LwpVgRTT`iBl6eX602u!p;)(eP|0I(UBh-7Am8UU z_7$=!!15Vwp|2`58bp|Yu&n#9X&x}EhFJG`Dj@%IEdM_CNq%1O|B8bB!>CT&<#XZd zXkcOef82#h{$%I=4|MqtmMO%D$SZmPoxj7K(UJgWdodPl5R3^2B?vN9Mai&%DlNUH zo0PSE*oSak5EUG!FSC)W<7~=hW(qj=_U`Hg;TRSSs)FQ(wUDFd>!TCi6{J{2(Z$|; zBq9s(*0HK*CCwxrzE-z|9Z(LHaayHpUtW@#5}W6vD!CV5jZF`u%3W8 z;Lgi))uu`4u<&M9pkk4Js=^XmF$$wYDf2YO(j6bad!N@kh6S$DUMFdiURDf-Blu9Y zXWMiR@(EeH75*96=tSAD{kA7GxIRUg#I*1sD;jc^(>!2b=Nt6Euv=R%~HCbp_1Siw|awEm~<>ua3YL+wVtj$es8O{O9J@q;E9-gJrV*$Km~N zZ3g~VtmeOXDIj;lt(-IxFZp7&SVqC{U4X5v4E%y7+LbB;9V`k?lrj z-gV7|j215U{_`rq;r)gzSx`@C!nc)9uTN(jPP=K&U)vwPA0YbhIFwO_e8DV7v^0f? zgWd@w+r|0?`cvqk_Uyr=-e$XAPW9FXgSge2&%J%I=u0#kW?>c%g;+z&PcL8Hw5!hm z8ov}5VPH`@R1-BlBieDgmQlM>i1a0zU9>dYri8ah28}hA(3WZS7$&lKb$Adqh&_~7 zF;sNaiK3p^wWP*FR#N;cTMRWQ<(!N%X{IXGIzt-9L1^C!Le4Ml&IETTL*0@yAsY2m zhfVS%LwArP6(u_d5GQ4Al+r46WigkFKAryxh~8)csxmve$?fYKsixaVL-*Mv4NFqe zZLGV@E22d~-DkIi3|JIFzd<2}+pC`z%3!$mH5YL8K-Xr6Wsx`rGji=+W7$P#3NZ(a zAtJRSFJE;7^U~XSqzulgXoh(^&H7q-{Y*l3x0gv2@+v*D9F?cCYAy)39{dubzuT#v z+NSS^ZrH@LC*nP#E*gC2$JscB6O=Lwb2i$%JD=*BLCcXwyYB%9jLsLOoMX>KjAANq zvI_`+!H9;u07YiF}~{TXYe{z#>~NIq=DU_Hp{d?pgemW@3&DH$oeMv=)LVz!It+M z&kvVn>a)EJp8pmQ=F{8pv&?|o^ejz5?`<}ri^5~fS$yQe>F!s)q&*+YNpd)J%8C5{G11YvZplSL%BZlg5}sImFR! zA?IVzI*c%W7`tyWKNT?B_yu8ON9Rzyg}B>&AeQYn8-Z>0>jRsyJ%M14OZ13tke8-k z_}k^nu20lRZnPksepIdbGwS8+IsqFN+l^ELb%4F``n4lXXo{uW-K{8((tnU4Rmoh@s>O z6_8`4H}x{gJDPC`z%*i;?ImeHR{p#-jcvZEZgwa?QFF#0yp;bquikdL_r8O<+EGH* zE^&-XIHXBt5kAKVC&6{{wGPv+b)b*;hWk?{9(`Z1+dfMK6V!id4gQwhzbfNj&A~qh zvA>#xf8czR|H!rBlh$PmDvgi8))S!q5%&cMsVsmZK$C_(Mcz{0D%IFOxHfVXF2LsU zoczPzH}~Dp%vm#H9>9Hhul1p5#^p2hnQUWHfVl?Xw|~rTH_LI#ahmqAecrDj@co)k z_ev#WFcxHiVN$`UxH?grZo)h)X2d*gDp-s=OdldiE?iv1uvz4tCR1-r6+|gD&a|0G z!Blu|`Hiq7t=LkEM32h6wK8Lv!ssNW%}}z@&RthSH33X|oOC#aW^yK3J62?o(neLS zQb;%XBtu-{r~Qz+Oa@E^Gv~gpqpB$Opkl*lhoz>Zm5U^6;(KtVsgACyi&YO`X&yqK zvu2ByP$EBkOrM+^^t#284y&y!0(76PSORg3+l~Z#RRJ7g6&z*8DGnOWKB%Yq*o^0kwCPas@nV$Dw0=#om1>R%Lg&ci+pyC_k%uDDhhMx( zdU0_@LGYjjD}SEMF@qAfwQrs1@6WpFCG4K6(oDPTN6di_sBAYTq+D7wuN=Lz7{7YS3jFLY7*C5 zQ=F~9&s#4pXzu8_jazoeV9Ob}l-&|m^XjMMq9tS0xUM_14K_cCmg&-U3nod80+m!- zSdFvF88pLM#n^4ERn?HLCD+$(p6H90z+d@>xVG! z{?N0ngHCsb#H!G=Fq`i^Lj4Y4D_M1}qz3ZM=w|u3A?XLq40X_S)tE0(OprhtoOlOX=d_ER>(kM4>ULSj@_M9)hDRi$MT_@eZi|U^hH9l~6gE41`>#8cPzwTYUbnnRKr%cO zWYf@wNZdVNO#>SXAVpZ+ouGZQ$W%ic4#Lme3LcY1FC7bpt~vI@vF!`slSD6F3-E{b zY2_AjaUQbjOU*Vv;lz_0k>t(Nvdei*jO)8R%vNc1_>oKp0l@q2sT$}8N0T+RNNijemFE^4T<~p9*y5H*l;>amM6u>U?FiX=?iejrJ77V} zz3p)H6dfoX($~hjiw-Wk!9mAldh}EKJQDOf%7^lEqRNUT3QQEyFOvZ>XfRB{0VJ6L zBgzltn}}$wA;0UPHimXh`m$zsrW>g*jquAFbD#?6^0$>v3F$eLQ#`85oWn5EJ;mAy z+Rx0A7i#7;fPNbkB9Ske-sH^UyWRZsLhZ(07|M)|g=y{GkVBP~K5u*q7uW`MM2No@)bD1IL;BE~TJr`7v ztKd1UFhe2B1&v+w6dZ7S0{%!EWLGS*^gTZk^Aeo^Jozd&5e-(HnFY>;ytD$L8QK@S zZ`oiC0?y9njgE%4 zHk8e}7J0O(igY#>1fGEPOe*L&5ZtL<+-e(-JcMh=zg}X$dB=j0q3B_eNja)cmvb979_aQihA z4U5rr+)w76Q}yn*$XoeslJ-}C`RmEYunS(V@H0kJ}__LUUk zu@)oNezKYi+TtITOmW|rswyy8`qyN$UtQx=YBH9@7f@GW zIo6U~Bp1_EhAN|MC&p6SVlvWStTnUdLW)NR0y3mEE7xdT*r@G;+etOpE6r%d$F1Av z=af+EGNfRh7bw4ZWd>lZc)3m#tl4lq?G1T z=g(kvCnUSCsIc z`0;ceVta{b4riU7>rp?Rxx}HpIV0v+CP~X&oq*w=ZQvv&3n<0P8ZR1SvjUJeZ)I`v za#op`Ux&b+mFq~dem6PeE%`YVZtmeX7nC~+Pb(X>m7oz(Z$oBO40?sYVq9w{-LQ9) zwuF0kWln?d|2?zo@@TNt_Ox{Ndr`dCh=(laolChzUWgi-8#T&uLoS(<$R4BPsBsF$ z=zJG{AFT&l^d$}#VQovms`BtU%i0N6JGw-TJAt`oS}2I?oh%opRp!j9mRrShZILjCX zSPcvtrf51+9L$x~wfH>x@uv01;fgABse-g~4OZfvY3x*JVf1)o%ykg*N>{zo_)MjN zY2#V2ACJp<{gtQD7DFs{l`}v3H|=mdU7n-iefPdtX{2l70m-yPNOEX$1%P4Z0H-7& zp*_GQ0HJ)9vrXao#zy;U*ezc@d*6uR>7r1x)AuFOqL zwmBA7S1u$q&!JTP;#F1pjm~?Mam(h3%zAivKSM5SQRfZzN?}*B{fkmhoVC$g{*+tU z6TYg@@4YwC9EvY?3B{b+G}~}VccNpkvLMX`omr3Zoa&S4OX*C&6|O>F``Y5{jaJ0? zOz8t>^NiDGkIVZEv9u4$wnyT!2D5-v0=Yv9eTjC_SAm(=1acqJjfw8MXQ_Kz3$dIe z^czOQHqV;|lS*F}=or^{R;i~|v66O&hjIz+nw4^jUcVDnk6u3z6$8~i4;2IL8jg|; z-TtO`XPepp!a~`9c{ZG#;()yl$Sx1VZl0q{*ymji`alnJpxXg&D|xq?Iz$;db&)WH zLcdp<>VXmBn+~PD9m7E9#FSp|obh39Ss>UsUgXti5A?2;)FkdAC25 zu}9}(f3e~chF*MYT(IMozVhjvxqCL{3`og<+!BZ2D-G{a3-1wk9U=jYU=17fzr@+| zIrc)W+6%Fak8|ulaO6<|AeY;B+^snXP^QS~IKIkAWY#hR+To6s`d%i$$gTUK=tG@q zBT!riEt+?|0UUZQJ3-PMNM^V-aL3)(@`Y2MMkxSe&P<$g4kR^PJKh*`;n3@r9T6#x z2xfpdZ_EiZfP$SNQY8CH*=~f{Q}5 zq}(fmZNKfR39WPahKP9H!^}%3E8ah%IRuT#%d3YBfY*qPMs%$1 zvpf7ISKV!4P6?J_Y;sHhKqAF5T(>kH?;^UzQcB1iD2iBEs*w-16G^gNCg8{1iTA!~ zIFKjXsX)}`#;Ri#>BZd6>WGOr*hW|y8YtR1F;(M-3GPSoSo97sW8sIAWiEtP0Grbz zWl9*1m;RnXWHrqGI=}B(b}M8zXpYCr#ag2h(PXL34WyGA0=ER|P%Uf8WXOcM;EO0O zKwgNUFN87FXp|1vj>Swa2H= zJ;r5v%qLG~D&@kJ3sE!lbtEK33k1>=1bIO4P_FsDpiVHZ%s^G_KWl5`5GRto{71z8 zZ$-@*(;Fe`%Dmv3~tM{Ey*c~a1*h1+U%=S#-J-jUp zw*Bg@Ct}Ttz_il?OK&O;(099YdQXk(qdn zq8Uu4f`e|>|$npZV)VcpX~ zrs{F~Jd`X3aX8bwSu`7xoF3d>k8Bxx%G_iXdJLP1Z;m$hQAxQS=megCqN_rs*+gAp zMGZ5Tg9Zby)>hmRVSf~4SK-l-2Ag^*piu2jt!i&)Gkb%tDV<;$DX&Va2cCykT{YIz zR+h9y2t|p(W;n+%^xmZcSyl9z5piBmC3!2&)bT>401Z-g>o=REY1=_3__#%w(MfcC z(PKKXUws}dgqN3{vgD)yx^OldVYG>s?B#!~nQv>XbI3DQz?xr#4_P9%>l%M9qI6Vr z_?}@8xz1e6Inb-ca}hjVj@!m&hqIy!f0`9BsMhcue@LtNwi@n6eAK(%!)E-{+uaH~ zs@+P>SON#1(IvMb+g}O9#-tFLxPd0%uoMy*Brs7MvNMdr>e+-P`u@~y*F>08E|3lP zX&5hD{b`+ctLZJ~1oWr7vpO8HB}aZpK}QSQ4eY^~?qto#c+*tMq*y4b9Y|=CYj>jU zV42EcY4|!SS2h;M&8MJRFF$Vce&Rms2If$Dz5!fJFHjLJPrY{2l6gZEOX87g_%}c> z%cr7Z%8354Y`22PHIF(LpB1%sy=Ruq{*EJ{fUIlE2vHOyYm(Ju?>o=cjur}0ESNIp zn^vt_N5#c2o5L_D-JLquE4fq>lqM@D&f0etnzOjogoN@mmGQ34{JXlQ&<|q2h~x2< zl!rk&@eb=;t1Vq^X8T$dcAG_fK=WeM-WskaN)|(3O&$$@2J(rbBpAp~`z3$dt|yks zbjybq`~wcAubf@u$pp_bx2rnZ;^KApxZ!&gSSL)?>LCpO^A_*J5*0EkMgE z^K=f*#Y&LoB>fh8Wo(Nm;*Zx2eZe%nB_~0VJG(ts2M;C;|Sm@at-g+i}Q%WFG4nxe}l z`qS)L_6mA!vu>oAP8__zA>7!VS0UWkUNtq$lRNZoKvo_jn60`-Qqoh<)Fvyi-^S;-KT16K#@pMUWR8kcZ_4nMuvwc-9#FTnSAo;ClQSMXOz z@ISe)|0t;Ntun}aa9~#F$(lIG45fam@`OYYDvcqEvrWzkxP3jwp9NL*btY%VZM%I9 zgTT3p>ND!G!sjyf?97df__LtG(lsn)u3y|;+Wl;J;!FJGCp{p13A9HJ+fxOG@Ddm>f=;{VrQK1v>(`oy=J-r!gzy3M`UT>d;vY9_|?ics76^<)o#nkbkD3 z*fzPrW16w@wpJj&5uT92q0?Ng{_6HDz{2-Ct@P~-uf`bH+(Z4=S%h;#VhCmO6qH3$ z;UN}Gg%Vo1hiG8huY1MOYuN8HcASq9&OE{z^%ce4XIQ3>Azebf?pqXEZE7wOPWJoj z@sq~qsY2%23T97{)5Viw06DO;7hy>z`N3}l2n1P(f~DTu+xbXFeNIC zb3>Y)AlxR&h?h2Lz>g=46Wg+Me4Z%*k<#tJm#jJVCD0?3La#wh0Q_Du^>fWCGG1A zY%NR5g|Y8Fi#D0dH*FE(XZ&5?6=%3MmA;iX@?NM-QZ8nyPGb4TU;5Q&9$%I#B}s|w z>{yY=Q89x8Y-!1gEAusIM-AX$c&hcu81BW|W4lGZ4xWCWzuRwpJ3Phm-(AivO`^tB zEkm*uYD-|9Vd+wmZ?yrHp}h!6sR7{q3n!S18JAr&9aZ8-VC-A#8PwaECEOP|5 zLfuERPF+}1XDGf?5!mXv5a`a-KTV%`#4nJzlHE99_{F^&kXUUBT)>@caAssd0HEL^ zGp-BA`~fijZHytIYa3`Uc;T&aiWxaD)HW{|=Dr*HGa^}nI{wi9k+5*HJD*-iY@SBt z;p}_Hyy(_^Vpa?Ezj0hA!dWl8_X@g!KLuy77dHZLbm?CK30fwI14VXXW*7h z=T~80F@k(yQv373ItBaoOr;^v@F61~_B7D_kh{ zv>Uxe;tb;FyVY*vL^FrypBQfse&hdT75D6X(eqbvc02yD&iF|jRrrqy?thE)rDAVw zXJGuNM5{9Wb7lFjxNViHmC_&XsFe|@&@P(%cfL6cn`jH7gp}eksHC_#j@?~-eE);- z01V*Zok1uIG(s=J_ zi;TIpvDaqo=}u>lsUgE$T#OY_Q8Bta3VCvi=DN}7%5V80q=%!H?!^Y_dE6`f8x9@I z={)^2Z}`50RrQT{R%IkM(}#czAxGEV!}<%D5aYzS(TM3?+ukwBZC996$_&$sl^Auz zgyYtO)M@RtHI#LxOwNHjk9Oqvht7oSB3j^(F0LRj-Ta>LhHSE67CC#P)(fe2ilvL5 zEysbVbI*i|pd=ITZ|l^W+&po8{1jYE_}g0uJj;8Fgy&GJ%vS~giHNT)QUk z!cwtKI)Z(P?GbC8=+ye^He@-m^64Iri8Dzj4J&G@p1(vl+A8*)u) zgjHXM8CLgz@mdpA*8vy$nNsFh0fN&WCcavw?2V#qFzr<%IduEd4;hp#+4Pp&97Qdr zp>`?;i7<$f5j2x|%8!XF+6@;RDs=p+q8CPGXog9$u^yphIB_qlA)LPwUv9t7!5 zW>fl`>k5(G_5GyZ>Eeoe1m`!OkaM{5*AZE+X86ayP?E%?DT1AJ`&D9woHCtX$ej@B z%yb(1hD@KXO8)H5HN)_b&^PuGU2+mKy6;Hm5~O*+zi~S$Oir(P~- zCyUU|eJ`YiMrp*c;qRiQYH4%{1I)fGqsEmP*CU^3(dz4id zi~J}CCA;z48fHWrk_**2`8rMDJZX)*8(&MyD76^*(|q@>`sl&!{V$Y)0afRa=CgA& z`j06-5`U+2{N&C35lmTlnkbqWeNN>6EKsTj)-ERhttPEf(NbDhMf@FPBFzSj;}8k8 zYpJ+yAwN&nDM$$p%jj^iY@11KHUsq`uev=nrG87R3Yosy=y{`t{l|raio}3?)yNtQSJ!^arwgvuO3ASF2hFm2azRR! zv%yY7Ss~|UZQ2FOS=Aq!DY;juXM>)nUk{U>CM|<;p?_%RNhZ;XW#8MABu}A3Ei|)m#Y`vkzSZMsi7)vJ;Imy8?QQCO4T^&yPYoyerJgo zQQ=LvmVMm3a#Tyyq4%P#*sN`XCx>GmuU`BbR>fV7Vl6QOKca^%uNW8uzRk^&-ExZC zt~ztBm^Lc7m{@`BZYI+w!p3gyd#X7Nml?BZ?;Q$F-BOLA?k~(M;jVY@Yy9HB`Cd2A z2B=&r``H@ea%Fshg3+l+;nKMX-yUwv>9sG^m%n~qsW-^OPNCFy@41=Md45e|_xm_q zg-%#FWqUg_1pB1P_WeVVr82*ISNL;Tg7WibUL4!hLAW0`(gPia23>=uPTe%#pe_Ih zS&SYbZ0m>Wy3=KIvkEUqofZ)5x1W32&Fd*YYv9_NQVZr<%LJRLmsdK3^|H?Ivv9U# zoOZwLYKPr@r3-4o+*1r2|7t3vZ4fk7@I{fC$97L)Abyy3#)ha#WTab!V9pNHGkRot zfMkOV3xzHDP0b+aw;Ll#Bb3h6N6d-U$OXUi=m$u`S~|v+y>0zGnS^7|uQ2)8gZOUN zU&wWDmwI_T{IQHus`8tRXP#+XN9sz(`(bXP{BHwzqMwCJ&POJlueZd&xjKt1D=GW+|ekNAw#QN-)&KM_pcaCcc!9=%h4v zG%XvIh4dsXKNhMShO7E)KL7y9l^$`L7$675m!)`b(OUzR4Jh-}yiQkslbaKHy>DVY zu!_vgn8Yz3}U_L6EcL znKvu~LyR3`IEu_Z*4%TrDHAIED~vVd+wEWUs{0Jk^XyN0RpckS{Qu0n{#z8||7KqQ zm$v*LbL64gxzlInGryIzW~X%pV6UF=;K-&Xi^3I!yiAF`exJnk9a4dz1!zojZRLD~ zT1|7%H4k;Im}d>ue4O}jwNIWeNCrd&PxEA^#`^-|H)@;b_S4n1g@v- z_NU)h9-B@vzh7hBw#oC2?$0SmPs%7Rb8AEyyfQ|Y)4c;nnPsv~ZgCUOWwOm~Wy!V; zZ*9o74Q>Nu=$Y1{DLO^AlTW=AUimt4i_}h3(!U`VvAyQW@F!648D@A|l;$RndukAQ z)Ec7RdP?To+X9%)9^yMhxQCB^SZTHyVg=tH9i_R&=r}vP~>ZP^63D3uJzS9dX}4M>!ruj>!V*BMV>lU0_gRJPt2;-_YPn5S}b?3M4lB`|DHVd+o{w(hBHIzNV+(B`mT zz|bW{M0$=gtu)iJ0!LXz_HerXjEL>GR3$SzddMWbLdas0>Bo*M1n2L5@|9Uy3CU7I z1`7%D)f$3T$|(&qpEre8x4@%5YV1o=WlD2H2U*GlGQ)j;%AQu<8QisMv*7FsK3u;F z9^k`iGAO&kc=m0zt3Y_?f2#dpUsz8A`yJ`Hm;=r6X4KHedaxAH6a)CM%zOQ|QYc1& zL0xP@bD|`+D)3pl8q6)cf$7ODR{Rvs-|QDA7+kJFH`i$xvY6>Ee?jHO zh3s|G1Y-Jmwt|_L6${jAKItGl-*&@1k?{kO57M2S`|bg2`^;mTH)8$auEnkD3fi-< zi*PE9`q&x9%U%RMLYM0H$2ujxb>wxXYIei8ijnv+Bzk2&E%`-zu}sx{i>qlBF>X&t z)pq;zDa9|+(}Cemt(BM;Pmu&0b-upBP)Yhkh;&>N$0$jH#C;h611Ho6-4iZSqxg)j zphLNxmk=SnX=Jh@fZytx+hV=;n4yAdcJ~$7YhVJ6Y6O^RQzVRYBg6h7d#gDFc$bWf z9Df?tG?bi9a-kbaO1GgAtAE04ck09h4^E}mJt6OG#N<1KM`nyXLgMn?J*Cu8S=K0s zj4ShMzcGE{y9_+jss7w(VWcE`qOh}i{#F$XatZwmhRLgBW<97hNyn&oan8`G*}YTx zH>481xpQRRMjsoEY4({hTk>4v*JLNhiY@dq7`c3xeJ|mZY7JCqVkZcWQwKB0)e-?h z2>e%!+v5n*&DBVVD8rt?IvU3U2NThJkZ+>H^wHTHfGJme-zU`x5#HzJ?!d5&(q!Q{ zl2?`%a4CPgr)vcF=S}=?v7y^q{XapvyF>WD{LVG=4GsNSxvO%mll^lOAAh>%aJ~@* zbsDBIRl<|Nh`CE!Uad^dryQC;PLN>rKj({iF* zq#RW#**tl#9JxXn0L44XO-!7I{f#AdnLbTx!K4ciyIv<6p z^+Q}*U8f17k#y)_lnpKtbCa#|#7Z?IqfzA0=Ra0KIm5I2&7~6@NhMno3biE_t4S!; z5`3yjApYw;@?tW{q12zxg@M;A$O(HTJt5utO4L(>L>euFbow;R;>F1J^T0+pfJrHSOlk zGe2WNK%bz^;Ozx_b&fF*=tx>fzm@G6_hP;E^#p^trR#yWgzXG*=J$$%Jwb{SwWRHM zas>1Yf;Fe|B2-J-x33uOWPlyBn&*@vx#^E=6CZy7adk#VX^O^mg3zj2WMA!tf5c~( zxSgtaB2@oIxo|ESdT!R)-wwI?g}Xn#aP8JcTKPfhx#92xhl(A~igLq0A9E_!q~Xfd zGc*Q>e9Op!uk)y%XIdxa#xo5xEh0NEGL=?R;G^}FbA7o{9r^IBk|t(tqcgSvO|>n4T7ligbV z{nZofiX*{N?ddCNE@*Nb5w!tnzDRN!vRa0!WZOPco^05)(XULa8RHN zdXXB6kYB!h#rdCo%fD~L|CV~>|KuzGi+%5ZFI^dJ`vee0KS;=2VHG##3nj8tpo2;k z;wTW2Gxh6+O(*NEJeCE!G$U~Rg!3vzzf;|@GQSp-@Gq}FA^2epG45eb2RYldvmGbT z$)sJWqgi)Qp<(n}tiKfB{rvHk5R@vHXmy@c#&!|g6c&$+-pUK(b|!5@pKsV-b*~+k z@+qyeTM6%G-sXc$`~mf*_(v>NzZ*R>r)=m|%J~%Z!av`jhKO%pGfW7IVSwryRKk!r zW1(;UrT*Zr=vH%Ko7s-fkq+}eu3rC^&+-3W7yMC4{d4_l<@Oobx;f8N3>BCpC5Rtk zKFC4|D~fMubsA}iq)GB4qV$2R)g}~RW^Wo$^%2CMtM~lH%HQO4u1N1)f$pi38O{Q` zD5#S4$>C_jXNvDBllkRWj^4)?dwgmSW5z^r_+>|JpYo9N%@zYg)z0+seKI~~2kKa+ zqq}EZ7_zRB{=QT)Tbx=`9y##DYDi%$YzFeP7_CJA@EX_)jZ9ab-4x5(Bx#J9s#c`gD z&E>eOGm+!d5&*KE@ePfP^vlFt?)Kbt$tV|A^v>?7g7S@y<4hS6bcX^4xtl+5yHrZ_ ztUlR2cw7uu9^Xh7SmSf6pyKeLpqXXWc_9CEae!DpGCg0;vaJ6S5- z<$m>Mgr!li+M=f>=%{|v!=Qt^M|1V$>k%1$o{fNQB3Hc4SdnQyqXLN+xj?juZl0`q z*Gl?ce{NV|z0B!i>Nbn{#8y2P#>Hc3nSa;iA1^dKnh!kJNz|9jA+8kcj|EM{@0ub; zY0SAV)P7YCTEeqgr5RP5IPsR1@4)O$P^RH1?c5nrdyR=vXE z=xo=@yeYTsBny@G?uR7j2EouhbN)bw=FQCdu7jIHp_iVuP1KGeiY7UDV_9Xd#FS)> zT76d#fc^6=W?uxW$sToh;kqiA54X`C(vG1n-(~4&5Wbf-v)=PB|*E5n8rHtS=DUiqr>q3 zBJCZ6B;B{~&+abUwr$&1mu=ftS9RH4?6R3<+paF#w$Wuwo^yVfbMJrdoS2EojL3{9 z-{kXRKl{7)TA#HmW1t`lkng=z*p^RU7#nmt@gG)s6C`gv`(#tsKNh@#NrlC^T$$PQ zaunsZ2A6Qb^vL|97xCj^@A0q%rh|I3aSSz$?9F>=8W_qkQA$6LkwESe3{nQkB?4-`>|SABUSu>b9*r z`h2ao^KCqHW&|~x@V6ulWt}G7*e`qFZ>b zZ!jvK*|IYt9Wg;6IF(fcDC&@FMBJecHpjF?tOQBpNevY{qLqp5qRgn3U@buV^R4eC zh#}Zp3mk6Pz*jl*cY7l18(W=S{W-$7jgC1R1Ww7O{x&81S1r#!(yE9#IoUh?_h{_T zFMk!w3Uy6q6bZ!l!Q}dQS{UPQ(SZJKCmSrp1Mu{|Ef5rfeq#AwrVBG#dL&i-7toAS z!$KE4o>JF?$~V0rDg%PSK)BGT^1D)*(s7n9loa}6h*PPzSJ7emMb<^u@6C_*XP$4m zk3><3X1x}o+@`I>v>Q}zzd@ZYtAeYiqo#nX7Ri$9x+&8b9w&-T42!*y{1z9*OOP~d*4xsVL_tO%0M96_U(-EQ(4#Ska*CI?SWgK>bAFgK zzOfW1)vnfYqb5+?a$M~3G(hJ#Et+J(~bb! z>#Qgub@Zo-<}4G@mh+b`8x4;7>E73Rvn-Y3I&2An6s0d;8d4CreOSs&tq+o(Y>edPbgP}j zh3TlsViL~CXTE?<_)CqWL-O<|u_VPGUX>0>C!y?&I;vx@Cm9h{*j$#VO2aut?o$U_ z&PvuaY8=rdtIIfgy9UV3>v&|DqD|4Gt27#_z9<#OD5L(&-~*&4b@b{Maen=zgmEOx zF{YNF-obY2;u%aKUwBcP<$a>He(&^5l<(ZdHNfv?803C1;$Ci0&)<)3IDt>M_T;3}#&~AHgeL({){S|2z=T6LSHgq( zn@OcXQT=D#gK?$8inEaJh2pkjB9bJ!f(ARV#bbUQDT4==^9>DAqEqo9@nWx7(iaH@ zXcvJmWECqX^>zh-?Ppe*eDI9l|mJ?4)(Js3zn;Z>+Ucs(4C$-OrMuST(* z`Q{VK_mH?ZwN+=%GF#OcK{uBy0r`4_W&A*%Pe)#&?}cY?$q^THC&toop~jvwui_8R zfzGA&dY);KtFQLM)eW#sa$@|Q#w@SM@JU?-mE!J>>EFq2<2O(V+>JM!TL)*w^dYtJ zQIb_A=5%yV;_qaU^oHX@PFY~S*fwPKY1zN}DO8288gdB8^iPX@c(Kk1(0*ohX2?-w zX#yE3C6VkL*`LE8oRZ(=c8Qav%OkZXPvpL!5k+CW#c&Mv(0;`~*|A1fB+zez)b|-9 ze!c!_j}+kXs|%70ABL9LBb4>DCi=(=G~BIMB8;dv5_tz&IBMF8MzalSHT=sEu1mbz zC#U`e7%roi)4edhk`$8r9tw%GVEve-_fKv>UG2O*Nmqn*y5;z_Eyni6ApT+|;lCF|VN~+*yqQr$6jqWjHjfMMv+%Tk&6yycoNm=A^pPkG4&6axckSAIU9`x*|hxmby8F zlmw*#objYoz!c*Xi^yMlEFM^glqtp41cy|1=A#+-lw5p*@|O;oYF{4^o(mQ!DCO`- z6qK*4m34bIr#Lkyi#8-!xsHux_9csSoS3`O$tlp-={yO>%9OQeBEJF?pSn*Io%5*M zAEs6CHd?T^;ih%T*T+vyYG&6!XtPltrhK&X1V96E5{v-WvEU0&o+i%q(=r!89{f>|d= z>n29lws=x^P!}2HEHjI?JtB61@zpU?$25;iMTE%-V}KHZMnru)$REB${b5~_K5*9! z{lG~y^R?Q};Wg1*U(H_;))R?#ap6G6QR;up@)rCjTOl>3f8PuJ={NeX$DZ0>M*QS< zoA{z+@pyE7=t2#VFSPZ74MNf$02RFzP{k50ju9~QWZkuOl`Hed3V*>aMq?h5nd#~2 zs&~pE=SzB`AW7%a%#cEayqC^uGi}eM@14VG6{M#`LoGw>}zMeR)x#K9`E1 zTzjUpVpmkjB#*G!V;bRv5vo|RWTNJ9-!&6jtyX^}6DlOKb@bCheI8mf3JGd#k^5a* zmWU^(j_!^-&Z@#kLX@$%05?yiEh}6bGg8u41Q=|Mcc&fKn2fqMMyDwivm-XFxv0r& zsaVqXwr+i@sGSH)KdFv4Vp>(q=)g0hX(0)+%x~9Cg}h^LP?^!m2~BS4qm|grqgUlh zQ+FSBc-)i5t5v0m43<-K3HrWOVrDV%GpOx1tNFWm^vi{2@>VvhOw{ZQY~$ArdPZw0 zx}$pJbe71n&T=j6Z0|@va}g3G^RQnxTc{{aMZQB$B=`9DqI`dn1}0(&bVgRRTX z8Li#5)!FBFl5K$&AtojKsWq7ym;kV zsyjy9IPE`;i<`)Fe({io7+sq7q7i3QXbYw&IJnCk$)B&JMp|sy5RGGdKctGVyNIF- zr^rG*#E;K?j+L?yY2a9cz9aKCv+QBg?VJ;g5mf~cJ_P4ia*BW-K5U-5st2y|*@IXP zzU7o;C$E3zhrQWGC$N*jw1!s`CbdtlAWon5AlJ3FSe+b@JQC1`{)H{pp<{%Fr9VUF z!2(56<AeL)BlKY;#XZ^U;(+5hoSZz zw5_c|@3_}^v!3<{`|Mb|(S>i4gJGN>Qpj;=J_1vgL);blxYm^T<#m~7;06^O&8?fL zMS)4-HJ;W}R+gVvVyfi^~$_d{$fqD0D-7o0LG?zOWzo@(0Ol=bN+#Nv{tkvv`mK2QFSxoLdgU8)zk@9X}WU zgeAgPJ!r@}6hiw#F1;DqXEXIg&t1E^mT$&d&)^J4;_ZF{w;ljQ)2 zb0R@qyuN&~I7WSya2Rstkf-WLp!m{7(!R4Re@o+cLHB|D;|*I#Sv3$j3kHf{O9bJZ z6Pv*?mmRy#H4kY}HzMBqv2|Ep>jiEa?HCaw8wQBfeNy}S6yp0Lr%H=NE2vQeU;-XIQINQ+tyOWE-#YSu2Ej8^CV$}YAy z%0D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%0A8{w@d(#l3|fS#9 z<2C=D5CBNYz(R{_k~mB>E|HRyQee+^4Yjue08+-fp}W1J*8E@3e>h`2Z@ehYVHW_T)CB-3Wim%R zQLmTxJbwWxlL0`=5r>p11MZFTBmj`o$1SOaS9{nK;d)??{}+%l833e=O`_Ks^lSle zC(|CG06-IQsX=HPWwBFYwp6<5KoKztm5R8CNpD)KANn@n7}4 z;~%RECEg-`fhp6hA9cpxb>D2}2;PGqeU=^J8kVR?Ki#lWlEU8nRFlOy7-`bg&o1ir zE9H%@&L*BVkXN9BY>*(u}QE|Z*s{w@;gMr2r6{l1cmpAW$ilv8E{+5hd zPDIwE3mjVCEk@r1#4;iXohn97X-ZU5pPi9E>L(3gP=bh-QXLSN)MN)6)`AwrNY;E2 zl(*o+9Z`hNC7h#N;-_Ets~}{c6pb0L-(-wc`vs)b001eYK=TM4s960CGeJ$hjW=y# z#j-FXKvQjPTa{FTpx#1@GZ}0yyk8>5Hxo4 zO??qA&23fSBzE;Jdl8z~mFmOuCrr(;*0Vp1hg$e3#;O3Sr;-1tdip;ko&9Ql+x$nD zSa4wZPrPD$n2r4W_)^HwWb%YipM1bPs!{*q5_?E$n!G&`adYUEbi9Gl4bultgZC70 z*7%*6s9okqXWUEiTFy$!i;9tcfi6u6dB59kSsZJ_cVYcItZ?Z8_l`2|QN?{|{`$!= z{BK}iB5-WyxZZ6;KH_;RGyR}!Fsi#tpU-_;XL+b~nkmxT??=%7oJMcS(6DkwbQ$ni zx8lQVnuBo!zjE+h1$tcrEaV6~N00x;@5gWVi>z7Elo3D!>p$DX{-dJw|Ip(4ZxG9) zL!pZ&M$`prRK9Y5zd#76yR?qWTx(||6Qvgm)W?sHa@%1QN_&^at{0bk=kAZ77rsp} zYC))YI!^+$oXe`j?Nwk3Bv{*ik#M_yM&}A=Hn(y}>;@*~Ns(p7SX}_?Jd%ircez@Q zstTTxFl=z_7DZp8Qr91K#rwZhV_Z(5@Ac{dfwF5Gq-9zKdpa7--)LVb^BeC204tO`878ESJl|xr}bI?NheU=$j-^g!I96v5nxaF z%Pi!NYIH`zsy(3j7xdoXgg#Q+ppDzT=b329yY%p337ukgB?Mw*MjXm7eL>%9L6jm! zIUNTtI;NekvNtvWxg@`N58(>JEg+vf;p{RI+TTWB>xSiB(#Az*>f~s>%LV{R4M#%& zv84&4xiCUsrtJ*d2I@4vhOJ5lLd)xSLUr<$7=H#*kd)9(ZNalmX(6NS^ZY_PRu8(D ztO0aA9t@Db5>e^Lo1;37GXC?p z!npMM;!!y7ma)N%O?lO^;<==8-cI4{T11&dsTRjYtl+qE-F}p@A^S@_bHtjtFIY-! zCbdGgtn$<`C&aPKjbxyRujeEw(l9|8uObu&oYF$=6`q{bzQbytZfA4qPJ?_6C5a+| zgTj>ZRcrb%ika2Vz7j@QG67N-kBVXc9HowSE^UdV*`|`rSU%A5U8pkT7*vKweWEsH za%Bg#4neW37r*&I0glkJ1bIU<}Q}x zl&7pzi$Ax?`rKMJVC#0&PfaF-&Bw}lPU_R+TXy1Gg<40s0JAPNKQ3J6(l$>h&WXNf zSUcG9ylUhQ%jL~mEmokUaj-mnn-Y>n5(w%-Sw_#?Eb%*h&ms@P${eu$JY^udgM@>k z-yEU{le8pRlVa?UG69pO#_V9Zx2&n>kTAi-3~hY@GUI&}&(E1bLPS@X)RZ=W6s^Bw^7c$5?aNAQh8Ayp-EiXHAM z2H!=yX%{+=&Ob;X`W$QF_u|mJ`#hB`GAZ29-CqUKDdh9&;r#ejoVoEdkaNG#iQT&v zYm3;uMCB(Po!bKwKN6a^@WZZj#7A||dFYvvIkF(yiuN?JsA&gEFk8o2lM?Fg4%fGMmoI5 zarDGSUuBPz?0H9BMZ+aZ#M#gnzzV+SVM5g3*g{(wI!b=!?dQ#L& z`N+XslY_*G|0uuIT&#p7KT{FBL9Aq|Y~`GB?s$fz0QCZ%!JH2cSeWYPjE(`-2_J)b zZ(p^Xf|+?duLC$FfCC!h$|{*%<`O@>zr~8Tw?&w<(P!4{6I>V291OyDOUs9TWBbDu zba!`Bib^-c62z{RL1ae8MnC;W6d(H;-r4{}qwNP8+8`S{h>a}>?{2#G9?14SvX@YX z2k89^mRND*xKUOuf1G#gbv~)9v#-CD5^uMO^R0kNwG8CHOV0kTlo0qQ=c6*+zq2`@pV5xn@)3)K=`moag~O0XIi!ad;+cOkbO zVj^=`SVmf0$({ix@|T67a+@ET@p=fJ9z!Wl*`(Z*uhA^-OFRU^NK; zqYC*SVL1Lf+f&xi_)nFdg$t4r^70xFrQ5JjPw-pVM4>~pSa0IFC8zIX;< z(`o%&3OfVe5ziLf0UCF=y1rVg5^-;47#D>t+&>!T7uwe(&kD**aFk)DC}qQv__!YYZye+G1O%lL7AVA7re$CDP86% z13OPEQJJtBOO-h4xq#NLI;ggS8yRhBXDb354Sv)&7AKP}msO%Hc=BhiKi^%2cf-a8 zUbPkn4A|-C)2vovM_Hhccbtf>Z%@Yt{j66(iH$f7dt5PAdk9xvMwmsZ0{Fcr+KhQo zN(Nalm*_OhT{2JT8h8v`cCx5|?idH=nm^$~OxSuzfb5l@hG0fHT)Fz^vG(R#}Ltq_G?rgV+6s=uxNq0*R* zaXQW8+avrndcy|Pq6;ct9V&w=*W!W7EFa-(d}*IkRY z)+{n`)`akS9s?hDM@nYrABFaMBxDV};;ouiU|0x%dT_Ructnds8_!urzvcQGuu=zm zfVt0@Y(o6dm$p(;Inec30-M|{k1_%Vg|RrWuEfUPz^s;CkfW0YC187dPmj3~yXS9X z%hM~J$b;4Cy5qwXmjXY&m*g-jcbJJ%OUy7Pk&jAQ(7*M8yH1rR7S(D4L9@QFoU?cgq7c(#D00|;Z0RFP%yJxtp z;3bxVwP;23_e?LcJ6-&{?wA^?i$~Cm=v3QqSj9+oC4WU3QucjQHvYC@EZL@%7wi-c z$WS%+AWMc#LExG78{O4y6f-GpZUL3LBoz(Ul$>3O%Pl1GW722XL2N5kM)lBLOG#Zn{R z5eT`%Ei|>uH<4PY#7WQI&|c5X(&4|Ni?W`jnW5gVTlv3Jvt%cv{pjG+@x8NN zNQc+sux|8aa9~LC^hF^sMcY$B7ib1%V;gY;k}iBXA3ku$*T54H4?@=jJ2%B;q-5Mj zFS2~tH_cy?kwYS#5-XzvHIfQz<=w5RfH~yLjsPviHdxX!yUOh79usphESlw^$*R{H zjvx^A1+;eH=qXK3cA3C&0$0=5mcGq)PI((g?g!gsEF9iZPT=0D15J2a`=#0sjVGuG zOx*u8#WYzjpkprI%{||#bV^CLMHi;uA+q9KuFFZXz#bU|PHRJGN{C9secj!(& z&(%}qmrxr5Wg*3yw0L~&0Y3RBkY7Jg$G}U_uVCi?ADvO@{>cyYXF&T?&J-CT^$R8y zs6z+ipG=^-6e2j(3;9Bbs=ozdRS1*kH0DT9X}tB}6OlXqU8($eK`hP2@vAFPayAM+ z%nYI6X9qGwZ7gIYcB6^>xI9g5q8yIJQ2M*n3oO2E%YkY%=K*#hj zzY3%?Z(|DY#JA*WZF3pPg!)7(Jn8{{v5e4LWj=m-s<>$=9yKC9cJ zxq?aHU3&mvy1^k#i^2QK0N?Wr@b|y4-G5IN|4+egBKEche*?P}0LbeAC**W0JZo`< zQ3;4itWi*0_@eaeTv#tFcBUBfD)`;NjDh*1P~*o3~H59=J(mQ*bBl%kQOkG;zNI18lu2p6Dx2Q-2h$0^WGh~*ISmk75KSnd^ zLNf?6L_`NM$uEQjC6>4myosE#>D`j6!HsaI0y<9;sTe>h#)UlDJf(A7u{Du2pgZ6a zZDm{=XH6zk1Me@-iyI%Pdt&Sm$uI=A>B3vI<@W~+_&9MyT}cJ_#YxRD{8f?Pq66v) z^NsMhP-nx?-voOV^d5zKO9N~$T5Fx77+?yRZ}wZ2uV56?XxxLW4vk}TSgd|hty8f5 zq+jVbqOVSAO;|LhjNWgFYnR^12XfKklF9onAY8yTRDIQxjdkzX=ZKN04tHfm)^|&+ zpw^b%lD2A5_{u-#5YEv$vzBZ4FwOYqe&_HI91{4A>;7)A<;(Ajvj6Jo9 zT-62Up-dCIQ{bOSjIpS?$MBi+`0-IzdLQltZ*9M5V`UHOx7?fGW0D?nvq#Ng0oks%NF*u&s$)5h+Yf ze8&6)(K=m#HnX$aF<4-Nbs`MI5O&Z(gpg7yv(q9hkQ`( zcQeOv=<5F=6 zq0D3B(5rA&B876M+lxzwUWIYDr?+vSzV?*>ArUNT=8uNM*lyFWwj-xSK&rgJ_g9ny`x zYy>wBl3mydGYp%x{WN^E60j5&aKhOa5+bY1JH=*j8*_HO?IyfI3bOGqv{Ju=rjTSo zK^+izQ0;Y*I~W$cWDd%c?I(!R3+g$-`Z2%m#IBIX>VKa*3^u8b%!WtCzs(;8Z3gSc z&bmtFBWjefHELIsq2BW5ScFvcYL?xRZ8xJJamhckT39DwP7rL`q$bX!{IS5cc3%I|*pkuixv$%LDh`fxe@76Cdr6s|&kDlXfw z`3YP%?fmBwxM!4HGDui4Ip3A1gNs7+66D>5V=z4Vb#gzFatrY@at&Unv2Bv$1sr%0 z(=|f7p?Qt*hn#H((6l#%zwP#CCGgTgeLT9+KDtD|>UUU&qs8)x2ZlJrnpA)wMuoIP z%)yBl5DTU25%&r5l3iv&gZEVeCRXasw{IDukPO&WEa*n^<}=9G`Eu%z#I61FhU6zS z&&w|TT-xr1z5WRk*c}7Jyy0dxxV03RJrQt5XW zygR#iLX@8c)qx=9!3(dWwu7+%+p<7@Kh%uD}80#2DAy8;27O6)_++A2O6-18j;2etW*kR57 z+Ks`g4N>czJLgOiqL6-{d=^eB=r@(z!vpZ^jhDw-d!jAqqZH|*HZ9f)&-K4RZt*TLNa_5=xXa9)fpUw5)RM9N$C zc)ve8W7~H*U-yXCem%eMg!>YD4hG-b_YuZUPOu~?6%5UYy3*Dz0dOZRcesQ=JKx@3 z*K8k(z6Yy@hI81N`S5Am%kt{AoV)wTzZ}QlmbDD7=83i}y4u}uUPR3+Vm_`sQ~%aZ zIZO9eOgT&c)=W8Tiq(O$ifcNFlX4AWziDKC zb8x5QF;l0nctUITNFTpL-EEIIZ~&UCXh~kKwyjd8{*GCgm7P;HntByt$cEkud7oTa zR%_U?k|XQr<@Q=ycqH##Sv;#6zbI}$^F=RpS1ta^ZJ^envbbtSN~rK`J; z#kYgOXhIh1s$E{*^hw$@)jFB>Cz0`|iCjhcpW6+7m|EZL%ZRkX#T$ZiO^UtvHL?<5 z-GfXV6laiknt4r3O|`R+^D~p!G=<^-7ZuPJS6{Ty?#+PAxbJQy#kQ+wC-jLZ_Q$vs z6z1C0vjIIMp1S+0y4hQKK`kjvy zbVpBt%}Elu(uUG98-`vkskrB{ZGfymTunVJDjKIfRR|j-FQ4mcOA}p(S`METUI?oK zm+N-+K?Vh+aOFPF9Oonom%~Owul~?qwWUX}$F%HQ%brW^HaPo2b^2`8Uub1uV%uuj zxAjf=W&Ts60+38St8HeH+GpAVtBB0t4d!-Zb!YOJw&i;Tp3>D2Tl$~+HLxB{t;u-NqE_c2=sL4Extddn!_Hm$cN1o1n6UCBL@)RuP1^yuIxyR6oM?jReSCt=A$AD+ z_&q|g;mBxa)byH$bd3%1!`PVu|mJx5E$+yp-9z;-g3y$3?X;H-+iJhr5`pLM0_tj3o= z7YF063Eh?qGNwySE~mJj4_f?W%cimaq(>y36LT%-60HrQRoC)<%{`f{zD!`7{MPnq zhGZ%D)7#0H3uAMqO?a(uLC*1&sshinT9<{-p+R>Dt+BADd5#6CnKCTvQ;h3V%mV_r zj0wum=urymQuiDDx7gnWI3OAZi*NDS#Xeqd9Unk!@a~Tt)RJc@IcX$pl)9IfE|vl* z&zmUml^wx#`DrCp8r+YeyN=v^jUCN9D7soa=!G+T@ebg7LHD>sIvFZ!2Incbe8!0E znIb#VnZEAo$9REqxOpLSr!W-?@vy_S@j)+YQ@&vtb_bt7hk#SDlR)uDQ(IFXuqtfs z2;(Yrl|pez*0(`%N!8ausbU&9E_Ll7`yo5vt+1vv@LB4zko=P-OqZ%bi0sd9o9XZk z`IoLf?iU>J3vkSH9>k3-Q^$8ngg4OrOBKz*jq#;>)yw6YI`(kLFzpLr34Gond^5j@TcC6c z6gDi1U)40RVh&9c|2IX`NJUd!3S=oz;BEG^l4!c3Fn9~t5tUge(+~0Nd^2@(pa1+!Y1TFF|M+VMlH?5Hlm;awOS&uaPEuk{bf!3RajE)7Fq50Q3FPa* zc3$kp(i4$IHw-m|i_JNzoCplfW&`B_A3%eSlmPS7w5`;66Y%3BzM{H~Z;FgpHrnvAAeT^~**(1YUdbUdn0qrKMDYhMy73iu9pQDd4CXQriW6Ff#jmU%~ z28AgF=3{g1>g3HA{AO+<5cXd^q`)}VGeT-V&exZ+6E#u9gP5aO1;KDlz)I{MIH;*T z_laXtSZk@u59q0lY%UQ-uf8sGN94|%ahIkZsfOK~r&^OC!{=F|X0TNzqp}zmDb$D& zaT^_}OOh#vVfTAhF|+himHVGzwkb(9xTAj``z8kl>*ekjr>V3fLO*A)##*S03}yxF zt|=Bt9wh$gsprp>qpxZvBP>PK-1B9+YU{&Y0rDK-(Rzbamh2DQQ44gI8#Ayvd#lV= z{7jSwM+?8{#`$8Oo=fw(t52jFEw-Z7V&1CMN;+Unr|>_FtTos2DJMlYB4S6s1j>x% z%M(`|t~T=UGnq9;U>)J=$EfvN+SR&~tjkNNf+bmCRcf5K|FD~!Z$5y+Y^ON5B=+gy z_|e*UHGC<3L&IDf*wYcL{Q}lVOAqWcGgRu5fMW8b4MtGQ5PQ#RC0%6X0tDl6hdSNV z2IiXNqF5Q?2=3Xa+-eA~4g&|QU9!i6>A8WP0^>Z)^mG)vNd&geWUZMqN!_Ys*LT~E_5Hd(P#6rPBLZD-GN}9<1j|1u5(54^QH*-FuH?5vQb(a}}j)tI@03#Gv3EOErhwucSUj_IC~FCKX`>D70UVMtEuNux_JnX}+@xJvy$W z_Kl%Q&y?zzzY)@;pE?^iU--`B(+5W9FptA3d3S+SS5vlqx0ZWiygc4&)HSz0*_ng`nu$SPmE4Xc) z%3+bwE4h~)_3rPJHUUx(mi_m1o{jpD)Qsa?5iQWN(Wu>%2b|x9ssvt{OsjFZpJz;Y z2%l#Rc~bLOy1&}vs8{lBmWEtH6zZ7{-f)?A7cBZoRKO-Fb7%^pB+2fq7H?}U`JOlF zR`_6}H1;~HKdW}u6&HW{`e8K>n@u&=zkp;|HPK&Lk8+AHjrMG`2TE@(!#|<7nFRbk zGen#0NG+TT))qslBU+u?XZ`~3?pS0A7q>6(B6PZDHY#C}PZ`ZI4^h|y;trOKJynHJ zh@;qrl(z$76Kx>N500C{ffyx2>{0KG3`k+*X`A;H6?iV_afo)&Vtb4W>q)l?qKjq& z&*N(AbtdX~T3c3DrEt^1)Q<*Woe>W8a$wTc4XHeI$!6Orm|mr6>jwyqlM6tTI|-~k zh|=(%nl~S?SXJQnOQEIVpFpLH*`@Pf#-vxL}`Oa^_fJ~Cts zPm@MfF-I+OLEWlb`lc3<8TcVBc)oz!3OVwPe07^;2}u1TT!w<%KF5XFwx{bsbs0+J zR8q-3%KY=Dm@CxAV&7cu8$)iFdi77W7akWVQ8XXO3fWjePZT|D>uKHS;0FL z2g(4COj@*mFV+6NYt8ph>V^MfSK&|jlhp5-+;k}{$#l^NU{T}}2XQ`MQb;~z2uN+) z8Z-mev+`B{kSe(gA5QXZcqS?5dIohf_i20V?{4w{EDX2}C@`%Qew zyOkvEMPXFR$hzM1&tB63lS`q8&f<+j33fcC`eWMQ)Cne#J-fn_622NH+){g&Ol2{P==frn)4}9q7X<6R53VAu%ejuSR!Jd!P zx^N4zMv?8uf}QG6zem0g+K*57fi_X5=$`0;0)BKZ5R*`vTt}C4lHD(3 zNj_FU)yUT*X)0~EUrnf`tD6y!c}NTG>vwQ7nx)Ja!J`EjYAh%bQwb!miReVV4A2P& z+yeI=S{G2IRqW#*1ih~utOx1X1Z5zJpf~XwEuos%@rdt1hJ%kI_)hb2d?(_}`796K z(S?l%$-+0*k1pu1^Q(c9mBnE8OOj~+m!09W<_E zA!<>E^Gelg9y`~$5hPy!Ct;GfrsuOCT=(hEXB{Iv?{9Y`K6V5AD}NKdzzc zGg6nUany|I>aiWHDeAcv?S&Z$9qv*s0)=!;RZF+%)%DV9{B0eH&#h8>`c9RGo_}Z} z!B_<5>i(BpLEm{4Ra&nT+3hDe4~z{8lr!X2)VUQTPd(Ax4$4JS1r_@z+@h6{ zha8(W3j&nHmIT;ua7sRda;pt}Wti^I=42INb6v%F+=nOu`MPcTjm<6iFQ66!IR#FG zV;YmWyQ}uN7&}|7*rM(t(_a+=T*7-dGSPYx_rd&bR^aq!>3UylP}f=FZd>We7~<5C zwqCTi>hEtCsWWy{;eIIgI8LIiPyav;ch+T)+o?PbOoZVRFYMK9@RNOrX2Evo8|8rk zh$Kd(_o&YD_*aS5x4-Qor<@93YR%X~%q+O5dcJe9yKl8xrZ4nGGhvMdM)Ye6n=JNl zMlO~gBZ1p1l%9moHxew~P0!p!wXK$OK3$+_L26wvY95u985+^2E>!4td?%{ud^5x3 zuM&)h?Igi)8Wxf^@=W$ zQAEJ^)#W=D!1tH1PF-MjVviq1zH05}>}bI5AG5K~J5u^C^htGpRM1n5WpmuF)!OaW zuB2OC>M(g1`5;mi;<>DpZqP3QR$6vCfBLF351iZp*1g+0DE0jta8)dc;p0?s=z9j{ zH2E>4WWq|u&x8V{A58=!2@OLHaf$d+7M1&3I)@s< zt2(2brXyX<*tFauWm-QtsX$Sj8+L;|`E6n5nvjf5t)PgB6{a=Lu?i514g8dTBAo5| za;L~93KTiIROW|C6ijLg`4iZ4*n%PJ=HgkdTQ$`Zv=Wg?25lsVBjXV=^g(*hhA=am zDdQ13REv?@7v~-0a!FdvR=mX|+kkg~QtW^l`cxSA2{Kc8P2YVrIX@%kUJv8a9Ai0Y zl(o!Iw2H66L_q{<5Fa#XTq0;gC+A#o>ywHs)2Je>{HeTSEh}1%*Jzv~3Bo(DlmuO9 ziifWu)8;Nzu1E0rW56}Sc;_gZs8U(GvVc)67L6cHmRy6t>ba@*tg{}c(!ukGI4a#p z?TEGg1L|;D851z)9Impkg`C_132LKLc50#9Vg-k^(FkcZ0+4V$MLkV9wj{MSatRS# zETrTBESu&@aqzr;Tgl!A#+rUaNg0VYlR)x2 z*#6F|0VYk3My`&3Hr5j&>7@I9aY6`*EnpBUp!|TdNxzZGhNbJ);b3u$QC~&D zw)_qn@So)hM?ELrF%J)?rp~uMcOz9I$M+KDs0Me|wOe8#6;65059{mFTyF+;{p@7& z$6KRpcfw=t^fp=!63_XWp3e`YP*?0pHD!GS~| z!teHyopITqZKdAG@5xw(Kn}MNV&x{N-B}Ei5FA~y zEn7kFZJX$<0qjOA26a^hqKJi!&HbE*bzX=KR?XmD{aD>ba(~9PzqbB!@!SSL?KEHp z!^pFX;ETpb8K_`or=t#nL`YGbF3=^H9y9Z`p_oQqLl|q5TZ{X`<8f&%-^-tKqT1S2 zqrjA5)iG#wMxUkPnB>uUc5Z1eqeCy*+3nfb9SPOsmDd_qr2-?;u5Pax{>XsHUv*6c zxkY8X&;n9XJ=vISP2X0C=CxRD5s!#XxeHx|8jgs%(HP8#IPHdrQ@~(FPBz7XLO-oW zYx&l0U14`mq``0~#ki?nDefBgwyIUgb)w!w#!%Omv$-EwbHi+pZQoU4GmbB-6WbuLADf3Z!TWEqtPBa^T9s`2z;oCPZl zT^Q(HY436ERX62{ox;X7s-iBB@Re*U_5d$I-rlJ0kT@Roq`)8`+T zscBrOHX!Hg83q!);!Ow~dBHY!aev=?Qf@9T8%ok8?*N-)oP~vh{3Zo?t8L;1^QwGK zsL_=n$w3}@TGWIL?%34|J54wTgVzi1zSN!@L&e$tNNGLI{1K*+xWmp(@IgLL1m_|} z{YOR%{lahcz*=6pJOOzx^^dd?zcCWOCK;skY;Db~O$3dMe;LF5 zOM|MY@$0F1p z56x5%46v#WA)LqE3EQ*R23uR2PFELTjKNpLE`Tnvn`$j8hbQO~#8Gm1D=K15X{JD* zo^Q@$HcNgcPhVZyM3GQwEop8U9fx$f?r~PXL|$vMtDG7+@w(t7)~`f!qVn_E-ejs# z7t=z^=BMk2(ks&4i*h};IVg4DetvEhyeiJFbP6Sj z!2RWRzhUM&%ydVw#}$3Wo|G1JO>D z5Ldr3fKIU-QLK^GpoA;ya|`H6@p0d}5FO6h97^CE; zR#P)0$QM@pu!vJfph-RUbAt`mbx$=bRGhDa;{;tVajZi+(lCdZD!;BhOeM6`hFCSo zG=tVhzbn%=04OS4oW_=P8>ALd!8j!8Gr#F1W)P4%6&i!i2gt{AxdhNsVBV&@pKnuc zk%T$-m0S)Lo@{jU(2Eci1aUtGJu!{zY4`kmpEYj|3C66{=j&6unU%9QPi#`K3SpT~ zmCD$Of`KzX;AiQG_+kldAtDgnRZrzxnn^ev6EAT()W$DUY`pB3#hKeX3RX4p%wTt8 zi$=NEIyYf`V5hi}Wa(TmyW2wdq;POE7dn0`w)|l^vzxe}fK&-O{V>TZJ|$!a3oLt+ z(@kY~l%@uJ7fIb4|0a_Y6wNf^i7w%aW?MdnCkpi|Q%*304*X+i^|%dN;@1@6(=Xu{ z9Tm5_3}c96k>Ftt`k)vlZHZgn)fd2 zUkZ_DKeqB^8b%p%e{q&qKSwb8_JJBnFxd034;>O}Js;+g>oLeyNJYT?g#q!|^j3?i zyy?-p?c7=LhM{v6<5k+*6s}@G+!gM0K->^6W5A2FEm&**^=RiH`-wU`5<&^lO?Hg* zFzId&_g8{5_T?QP4gdm^_>YgC@IMJ%%5=XUJ~Q|Kf_48MF8XT$y+X-CVO1EJ%R*xq zBJcyG`5XXII=cYSD>X90ApyL3@bGvoX(1V`M3%x4hGWaXArB>=lVblADv{5%#hPPT zvP5k8-`U-twd`wWtiSG`>U;%87m?$`wI(}2n;{6ip5cy(~2 zq5gwSHD#sEWh`z`TMV4#M)_6lVahRTR-@Griy&_pJ-d#5=~K|wRp!wpql{V7|c z_4kaMXU42X7w9z-T)*Q~TC2G%z{F=zI82FJ(Kx8q+#WQaQ%2hun2;WNvWs|-5~HTV zxPigw1|wNHCsMLN$Dc{#M>~*E$Crm}m{iW5)-x z^EbQ|ly{=zC4Fub9F-`N-c}$Yj%rF7td{#T4fsrc#6WNd377#%2gIV-US0<3OHH(6 z7^IX*gP(?+hRH{oqXGtOc9KX_!lA=rvgq-CNX8ot!RGn^-?=CY>L*I)=_}TN8iBh?U8HHa9PCglJB+mnPv=sg3 zL_lkzv)JICAIm>$CQ=9Dei2?F{B9sw|AvV^U^L)lL?@dkY-aZ)ME4z^^4kYReuqF( z8)lyoCt5aYgGOm>Rj}hgEJ$b;-fJ7d5iU&at!5}L7#>U#7NlU6T7oLOJsz-7Ffde< zj+JiS5(Zfa6G}-Di;Sr6@zT79C-q_?7UCk$U5@pAj`fX)qEd&PMULJ!aZ#v6*HoS1 zmxcVhAN_5np9$MUc9#jpx$>7kPU7&3NPlI9Fr)Q51s-wY1Z(5#fFS#(xjaUYb`6`J z&rSl#vx!+jV#jsUg`k`hOv!RMR-p%^6JR7JTdeIVJ+$jlQ$_Ro8*aKBSM!Vr$S`dG zBaV>ipPWK}+>-xx=%`pJd{#pCw&sU`ECCffVO~%%7pSHzZZNMFuR&h9kmu)HkzWV6 zoEp}Bc446^VR(|`DbB;a@%O%5C=yMo+z z4q~TLzXq*O5%LVR|lYz)jt9uGbJf+NpC5?2@fda44<&K#|{4r?W%M zkFDoRknJdG3I=yk*lknSl|DaV_?Eqi#0I}Ki=_7IDcJ$pyjfetzSB<5Sy3K#_@+}k zLO&V;si?>WkT8BsKUEk)P|wPKib^>)JG`LnCmNBM630Y>VJHbiR5WEp)zx7-%>&s= z-RizCSr@>w@++?JIbL-;$a6C}ZpLy_7yL8SbIPJjGgn_$vUcVNVkd2XQneNhKrB-< z5NItep?(%M0*)L=m65XgFiO?r0B5z$>5|JnfQ&sITte!;i4^!D2yNtg3r0&m<7;B2 zX~sLEmLiH{)k76PyLUJHym)|7h+0Z_B|I|LErV*y?G2&xLiQpvt>6Yi9{uBi0fYr^ z<{l(xNV@sjkw;?7hf_`>FU#CI#9XrXQ{ecHlsi%h$N*@+kdgtGO^c5Pa*xQA!{sG# z0NivJUc~T6X|_QJaMlil_c|y>L3p1ic$nJo{A&qt-F(D;Q1}HQNq7*XIv+;JVhw6V zT5f8^&}?rK(b@6hW}5=)IVyDC^*^!Qm8-6)k4;e zW{ze?4u9lQ0|4DQvI_iLP{(*JC3LRlfbUp+7v zV>!>^_X|3jk#IP56u$&T`4J0mi8sDd`9p4oa#k3yMDc>g#;HRFug<(0wYY;`SVNlAT z5Df~+!uo=YS9_JSKP5QkeF=lYk7~e|1RWYoYH*^`uy-WjXxTeREWz-CDs_0uEnzG8 z|CoELs5rZH(K=Xgx8UyX4#C~s-Q9va6z=Zs?!h6ryL$*O!6n!!zV6+vxB`+@^(Qd**G~3ml>5TR`$^Z1-*M$C@ z%CL5}K3tKXbPP|?&J!~=O4nvT(I<5&{|rIJCN%b_S5;k+>`HP7BZTFAYp%I*|xGtW{hCKC%nGkq9h@|(!jYDK*6(lt$ssabP_;ywNGR`u$U zbAP5Iju5=;@Hn5LNo*Rz3c3}vi;K8%nIjIcp4HrbJ%29e`0i6)mZ!ep`DTMCK%JAs z8bls#+aX`|irg$duKDv|z3!PQe;;>@QglbR(=5V|u?`E*BQ$h9rsiq+elxE9!L26f zV90hi4&GLgY}Qh`FS;e-8I*#wrD#>!jt8c>Id(SCxb0veycO%b=xg_3tG;2si9-I3 z+HXDy_uBVZb{)qJzUwV@zEiW={+}q3k^d0T#o zs%WTng2q$^E3F)3JyLIg0LiwCor7#v(G? z%LZ8>uZ5l=X@7NGj`zoLPW~|`cOyTSI9sZ@Dp!zBvcf*$&~jfMTNRt3s8u0(%7!@U zVnu{=vn^bL8+}WJH9NvaNVc>fGpvhz97#(uM>xua=ZA#yFD%m8fWo7qmG%*B41$8p z?p{31Y<^4-F6Y&&C=b<9EEbqiENAF(tj4ertYHFCoXKZP7p9EyFO#NGd!|tb%tPhO zLs)C42YK1|B~%A-6JJwUha!snz8)pBS|mgEMJ|(u2V3vNI|y=z(JBbbw;!z=Da+gz zQX{dQiQ}yZSi!M7Wyt+y$*Y(184%uDhOOXPE@hW zq!UaQc+)REa^=jsg-KtSZ+I&7^N6ya;1{*Sdi=59@ONj%o$`l@pJ-ediV1*NPwHSknsU<0mo+3+Ip> zhXLG4$z`xaF3&!6CZeNm7Mr55tXOz)i5i)*Pg3B0kn=$!+wyaCgeo;31r4D2-{-Kk@mOnQ}!? z8@Mr8zs%RryhskifFfJWP{6b#V)Fm?j=y=~wKX?esvb_!gt8sZT8FWnZqAAV3{`cV zXc_ilVmqnoh>h8>d_#(v_|+-Pva+J**!g=>wXaT%^16f}a0afmRm6ZEfzBQ0N3$Q& z4fSIuR0}T$Qo5qA#K73$Iq@Uk_Bx8Mh4d7~IOt|`%aQw29+}Zkjf;wOc%OCM$t2B# zlx0zR6_68gn`H!XwyfXfC2hoVzY745MX8txf#(scKMoo$F{?~NQ&O-P%()^zmdj0| zLao0M9^=uVDk88p;SCfS2R|FLwcB&Qv+b)KP_|M3cp*A|&+3%y`y)Gin+mZz;pQq=o zUWY5xbdM`1{M!dO7|pP$OaTr?vqk_>165*&t5Z?Y>eYA3kPRwT_cY1C!RYhOUxU$B zQ3-TXMaOSU+%C9G!<^X`V+`_y|3`Vf0}kY2JKezpKwB2!Rd!B8D8N z9v{EB!#aYg2&VgDG*1Wc%PIa)nFNi8;uQTQ>-*m(qlCc8DCfsyl&drj6ASNGnK%!8 z|FCC=7h=dq)P*2g-o$?D+Ku!ECaDu$YrG}1HaHU{U_}D<849_E^d~j5Itbz?NnS;M6hs zcyv9NN+hJ1vzuIZapOtR6M2pkC0+wpSoR5_7ijh%&=)AVMFb-W33i0_G9QaFw_`zv z=1gcDlFPW-B@nX9Z{;Nh+~)j9uF&YpZ}lb43f`!0AE(2Hzexoqj&&h&|52SN2%buq zk-N=H-Ju$!D`}09T(j(U)DY`b8X8m|J5pyZTJ~RSEGL05jt3P!Ae;PMJL5*}5ISCl zO;+)_JV(_9@TD#69$H>0TjT|im3ENS?4Asp286{_G477|;42MkpTpuM& zvw(-~@qZbO{?Ez9e>58X+r@=~jiKdVgVBGgu(MM=40KfQhNsihNjXNPubtLOW!rzt zwg+E4GiRrhCX%N!vOtsi@0l=5l4nl@Yqo-y05*D_3p{-$nu(Qd+6fWd|&N;{$#-Q)`f)oy&H;SX9zS)**`O4 zNB>C0kG&E<)!z@+1vCDR(hlh|xL3>+=)$I&skCYIF9o+#Y!U692i5*?VMl$mFy(>hB)lXwmB+X&=%qL9fB@RB(M;vhFB^L2lU@`2gFrE< za8NEIdKqYNFfJ>4@l8oU^-xzTZB%+sL7$V(F)sl?7q&6z78+;SnHq>abQBE_>5gpx zv}q#f7BXkm*)ixAdYTeD-40&>mT4pC7Up-^)pJmOr0>G3*`WMroCRlCp!_J0=%&+X z4iY=+$$Zki!=Te@_qZUrP%jw`hcJ&SJIl#@^1bGu)9Ux2Ai1zFfCfw$@PLk_E(t=I zPK{M*a9}?|c~u%>4Z>G?bsU@%T z@8FyI(bwthFeG(J=Ak`GoBEMCWc6kycZu$}2c$H3L8w7>s;;hstHE^YuJVAZL3b*z zc7V$veV1SDfKY?&6kqj%Sc2-5UwwvD)oVnvx{85?RGF5@CT1oU55i!!qFthWSb(WllH(uFCU zU3+b88I0`Tb|6y^D~vchbu9me^YpQ8DywWn?c4qK+4B6uf2|GlU%Rv@l&-g8{pG** ze96ZE`mZq*`gyD6?4|$VzfK%pMX@OW`meRcPt9Tp@<-NvP5dpc+HO5#*v%_p1owD- zYsXhntR6fqZ_Z`ATSywu1N_&tLvz^`7mh8j+qEq8lR{^uEXy?Mb2ERSRa)eKHm__g zjuc~Nn==Ep?rH`sCU_B>l?_FLS_c!?MSTlPC#(O6L^f8}2c6pEZ=J@Ur$({2bqZ>k zZy?`4z1Z2~U{2%COP&6)G&r_UCLA%2ng!U|^W3#^zittl7Pj+P6nCmsfXY@K$RHf9 zT|BVOh*@NCClTk4FV5DCTRy%-PqEv#4viW+y7&go@7wNXA3ncqi7~*_TDyG)J?DRq zzlK_LN|4vZSlwDc-$|b`nEAcAk>8>>dr|nMZRs<0zB&WdOAbcFs5#DUMMXr6|8Opi zgJbLTxof)+h&{<2rmfx8(?-65I*%)QySJ?ii8JaZziTb7ou4>~?cDm(M*f&Od&wty z{%~SdN_+nnL4}hCSMV;|=t8PA`rKS6CAXF1F;RA$BbPNDJ(#(Zd>tJq2(-z~-GaS)^!6TfMQLNmU;gWj-4FjYtNVxlI{h#IH73x1{cV4WZAAp@ zn@83O_22#1;|4(gH9x-G?J^{Dxkf>5&R(GA?U}1PWnXeB?(Yu5Tucd)svLE%4ME%* z69(IcDzcQY7SmAAf^viJ6moPBxSPwNGrYh3Sjzae?o6baQDWQx%1q5sdgJj>i1EK_ zBgu@?;h}C~>I)veWGXN;Pkg1Vj-g%3g)(oTf>Cy?dYw~>2L4tO$Q&5} z6lB-CM6n;pkS3%%kf+GZz`%0ubvtmQ%AS9TSVjbpXwQ#|__(_$_^>#ZR$zyqoDw@` zNBiVxby-dX=7@Z=*t}A8=-0aQCv7a3Xd)`H;@JICh*4e)msRZ>HOX|z^g{EaVNY|a z_vw)X?DWbJ%={`SFU!~Q5Bv50=gu-0#OzY)i}l0RAya9AQ?QNSI9#tg$I} znzNaRni=9*N04oK&*2=PJj%buD4Ks7&+6v~DFYQM%`Nk6dIh3iuFY)E3lD9ef1C54!Fy_6&`CxV@4O)q=?sJth$0jLS$l40XZE?uD=oOjb!`qC9Ka_JqIs9@CTZfcwIkZQaU(UE*TyfE?pnI6oqhMSqGZz|f7~jN8?k z8vDxF_S40A3IBB5(?umi-J@#S(DtxoaL3C-W)R_?-|q@~hk{=z%W z>S;?Ky;E2%{e?dXOR3HH3x6V()SJ6Y?p&+wEqs(uwY9dF{=_V~HFuZZ`BW2FyegcE zYav>`YMfGN2`v6eUz&EV*n+7lTP#_uSNW~0HfqH2{M6whZDew2;)dU z1va2nfc4e1&`%U&=iI>S(-{XU(bDX;_XR4eFF*avUTQ$Jc4SfEh1`hOCtRye+cS3^ z3BTwKN}Zym65l^qf_|#O4bclvweTaJiM+yPb9WKK*s zC0W6h2WYF~xTY5@rDMJaAO~q&vIxxfrZJiG`$*1#T$Uda z>{6D}iFD@4EW@dc#$W6Q=My{=t48T=KrrPdW#+ zna$U{2RG>qjHkai(ilv(Os7&Yne->T!`r_4CO#=0*r&tpn@*&%=o``}Y@2l_Jn@)y zbw)f{9avAG{<1r;PVcd%PuVu^j(K`MKzRZ?I8FDnpidSs>JE4sK45-AJ-|u#v!YKG zFy88aadr-Qfw+;K=wVeK(`VYA@Q!Sg(wgu}w`WryUr)0)@9x(j`EAl2>5<1+&B0swnX_Y{7LaZ zATx7cKaIfnt@1d*&)7HX>350tThLSP#JjoYuXh##Mx2Xcj1Gvw0Qyjf;(!`n*fB8O zCyXdW7jz8;^dl6E1@Lwms|*<-+j)sHM{>!02xp0-MO|qnn?6vK{y@(J6xfuwB(1uv zqKQCN(h>-3$uYW>uf%i?2~mx`vdmk7VhJ!G25dT@0lOhD+awSIB*6-nThfa5h&bJ% zubecI7Ajt*1*pP~fKW^*$AF8IX*8f2b%8|z8n8LDO-dlJfCg+EigepPs8L+lDbjT7 zzE#p2TF%s>rNA4>6WZ@_CfyL2iL`Y)N(mttI&uvofi#jQbl)?6fy362Y1;I;l1kHl z&oL>7;E1Db+!0II$2cR>Gz5yTY3RPEnG}{~ z*8#=X(LnKa!)TzmL>30GRKsfEu!IfL8~T(7ikyY6GMS1Mmt%Oqt+KMy&f@l@-W&LxG84Fvd*Z4{)Q2EgM1M#`ArgGh+G?nl6|1~O zHAwz-Y|hywI1p_PmzB@Er0Y;FtKa&lS~eXrY!QQPo(XN%5s}wH!qyOkdd`ss&P3}L z^}vMhxh2+?dyntUB-T5KtO2EAO2dDu(e38$p^}>z5itk_kaEn z=J`)1`2YK&#D77;+0lJ+K-s29C3?Cko1?uBm;1K{B5x4E{=P3nyZrQ%4daZ$C6J?U z8IS_KvCIfpBa<~Qs@xvsZ*Na8pp1Rhfl6PHu8Rc#5xLmo!MhdS2an%=&CqEeY(WdO z9P}eynAbGuVXOBzZ2V~!l1o$ZtusOPCW8t)EGaNuwY&(#KGH5=OrniuPAz_!jQw zCyZOV7wy&q*x}ni`6|DUlmF;juDkoLp8YyuBj|rl3nH+7W)QCFv+xaB?pVJrG z_E$^+rRDd{EQN3kUe;aSeuFIm6HuKT4b*gOSktw2d*D$hk5ForJqIcQ8q z!*cPYmwed-)Y|&T1B0u2aA3lZS-vNz`MWP9 ziz5jvTv2(dW@c*pIs$H}ZGNSzd>V)XP^e&l&=RDNlyO6KeepvL{Heox%4(qJQ=)q)%-`(kCyem6C2ZU9rmYo;V`q@t z-Xp^H@D;|;-Xn;>&=tEKvrZNJk6ow1)l@O3SY*I!t^wMr>y&p}pBQuIUr>(hG&cF&0w5dm@}Y)7O-Q>q z$cPSK4(nM+u$1u}G5 z9@{FVMT8AGXFME+E3B=aSYs@*Jm14%ctI3leiXWAh@g7sEyLCkVI4fCf=c8O;=9~I z6DJdUH~jYXVLOa~ND&hECdN+)RA4!P+&WKkT5-Zzf+HIB_IaXs^0X&gfMu3Kzd>`xrMyF^qdR3qwbE{b}H z-V%gKozxmEjKdJ5a^6@TBSc!4l@k4uCT@);?htEt-VMTp`?Z@@i=SlADn$}&VN*PL zAM9;cCUGpnY?*jLQj||x(Uo(^{JJQ{ogp8}>tAcBGF32a3cw3atA9&o3H~QvT9PKf zeL+jJf2_ZessQ&t{+r&iSW#9UlnKdaFxeFZU0~)&6~Vp!YNrng(Mm{2Xr^vUHo#Ds zR(I~3BJlg&&tG6{g^d)&-T*OMZacI4xO2Mp0r8VMCqg~uPk$nZ+XEq7=A>M0C0KNx zcqHNCYPNJQvMRE1Bo1z4CR82h?8_Cb^27rV^EkQhKIyS4f5uR+y>~4};5COgy`@rG zLyNL;C%sHc%Ue|R=PZ~PywXD{7M55nP4#CB8I6QuCaRapQRV&+0~+P5Q25E0IfSgn z2N^~>%1_Oto`wVCB`Juk;C6M%7vtdio9aDdtzWJ4kJc#%EzLeJB#g<|->16A%QFoi z3p=~UQ`j&5$gw!qd38O=7bpoZ{{EE80=H}}@4xG`zeWru4Dv(`4u=Ef)4kuw2ua+l zpHi3Izw)%|rg(d`pbVx`uNkFqUmu7%U2D|y#pka=fN1p}Gcn*>=J;RSga7koEcc&0 zwEue3{B!eD($>)2l=PnqDgW&WRx6B4fdOUM;f~9^tW4(i2YHx>q)=Sp(u_z2X^3%h zbDHE+QzH|k34WK6ypJHhNt`rB;8!SF!t!pIDyqxt&*L=y&Mr!4r54Z&=4fU1x`ITa z+If!K>VR8Lg(=X<0H(7VR*z}DohK8{=8#*&)3z3Q=0hl@ophJ8Ah=WU`-WOp^LQ3x zHe=KUZ$3(5^?SN`p3RJ+=YAdeJg?R$jXtnOB|TZz?S#TWunuWso4mZL@S51rrG2M9 z!=DmZ43=PH@$iMkOYv3wEz%tON}4-Ih+yWhT8a_E0jJgWE2LLI-_vr5?wEuuc`8RD zgnZD~dxCUm9UJLHC@2*Lens>ZLF~gW&SEl!NLh%x>9wyY?{a4q7DgQ9qMhMEMfZOR z&4Q07|BwJ5kI%n-JPQABk4M?T$<)xq*}~NH|FWC=Ih-XAEq_$4oVZv52?ZG?1QA#Z zVT8?W-q-!wjST@gl3%cLJU7EQn2U9M-19qk9K9D-jOY)Mk&wOf0y#;ifNZMeRq;mt zR>sdNr;puSnUCFES1P&5=6Ecxobagu&#vmk29&7{xq%*(f+9|}@}@6_PKmx-H{rr? z(76wm1k290tE4$MV%YD`0NC{fpD*9!a1A%OlMOQ~7tI*TDLOYP5TSw**7E6hK{gLg z@*Yw_3e3bU(vgA;F8?}GF-oLzOaMP8-+z0g`j4Wd|M&y{*NnB0tEG*Jsng%4(aq}H z9~|kMosfn`U`W^s@NifTJYeOi4X9AhED2G~00@+-za?%2hfLaSY&PXh9T`6>5O~i* z`Z#!B%}yyCtzf->dZ!$Ab`wUqHZ~FZQ`d2r)AhguOpyZBFK;)$fgn3)Y*y4E6NT~D zjT*!5%#7thTfq$sGGG**kpi2;L$1p-wHhnYxON=|vg(^oO(b4|5cL^CP+y zwG1AFX`Na4DMrSg^3BDCf=ZkdqrOEtWfl~;O-Vj;E4$ee`ufkh^pE_)EY4PQ&8{q| zX+?&wp);v&Fsv_f{kxVlwcOe~n*Hsi2j53+C-<=y4`M3YStk@39QpcX)u&JRSBz%q z&^C*;ycy1R^6OGtb?vy(LIVUESM~|<13>5!XMNmHRCih`okMp;R3A^Z0=RPo&Mf1G zsHcsr5=(U%{GA#lysy1g-ENcmN@eDq*go8wo`DS+drn?F_GOt`p5yg0sx)p&hh==G z7o=^{K2S9`fp#Ysq{58sontdh#-`u%Dl@(F)8rk!G^N8&!X~sWCp8vrbep875Zr`I z>*ib(IhZ%hpr$jD2C#$+f6YXetD*9$2$2TjX|9j4c;i^3(=cs(#vmHsL;|JIGV7~b zvUq9=+1%M3%@-_&UgN%wu!W3n6sPHNIuE(95(5VJCJGEWjl7<=uV4#G%OZX?uaW_h zHM&y1QHC${Grw$crrU1xtO>pvj>8t`DDpf`G{++J6HME|RJ2}wJ9?|y?Q}xPBkXEF)MjdxInBW;D#VA~bL}MBjb!W|$Y#{*HTV+oU6e^eyj*Hje=!T5 zn>N@Hn;|s+DSMGo>4#EqG6s+!#fl5N!k8!eVv0qN-}vjxA1g$rTX3R#_#0U5xx}2kgjSZf{v?68igVC& zy_vV-rf&d+M3#6VT8Wa1pI8NYCJ&O@>!KF<2ZySG5|#{gu~$=- zh`U@0D(?XqtI)Yy*f}qzCBPAnTAhemTp$qVoUbO=L`)G8n=x`+m3RX?`qUhrMM=)bg?Z%&Z4c0Zq90Sf ztsQo=Y;mI!?FjCOv}=i#fasn-ebinQQuIFJpBc-d2a%gm4u+o{Gl{kOTw38CGS(?H z@DrsA@n^&GdqiqD{f#CZ$pUe1osDK(_79{o0~6xUe77~HBCt3 zn2-laOMZNT6OJSXgc_w`u&}^*7NQY^lNRRb_f@%P!|v4wUwZDk=6_d=tIMiggP+{w zD@(uks-B`fILflMMsRK$LcC9_Oirtxq_tZ>P=ilQPU|q&rl;}rp5C(#PAm14Zo3{^ zZ;J}v>9+Hf5#sGB{C%2HuI*Yqf!ALFyJA6>s;^Ha?fzCm(n*v%nOv74<62VCX=9)G zveju=AGo|?G?me9I+t1}uUaL!BJp-kw}^c0zEyK#Ch7*)w@REs*Cj}l#6}y$AR*C` z@3$(Z7?N`B_L+@BiTxyHiZ65wt_4+IA!L10=Eqm&MY|h-6n?pVUBoUnDXqCC`*NEg zIjPL!y>AG_T&=4K&6%Mc4X2U9I^49(B;lnA}s*_;S#mQ=-A zhK7|v{2ASfjFv%qdkIJDP*twrWA{#0fSi2)FQ&TMGCh;LtiD!PZHe#gsWm$VCiC+@d=qrY;5+a8J%KyP=Lti{vmI;2e|6+rR}@J;JYA(DC>LT!NH*PguMCjo3^X5L{64 z_jXQ%R%8}(DxK%g$o4-JKe@fA{^;Y2YN@bJf<7?#gZd-2m~2WCwq-23+3ff890B1f zvlel%yIHsJRuoOZcc;J+rUKtJx?xp;bLh7`UI&p-S7m-7`KK>)yP9B`X2d3?nb>)8 zDJ8$q=6rGA|2l9dx?4$408ews|8|S+KRSo}&jr@MsA~^-I~$LG5+VN*N8esqP8|5x zIC}iw;^-A44b>vRI65hN@mJurWD;ocS6~j^(sF+82fVe0w6wG^@Spy+wDvvQ8Bg$e zHdh8G0z>YD{3yZOYqzuc)C3ocb8W->yw3w@FU*S<6Q_d@v|VqsC}%4aM{=*gZ222& z1qD6GJIWC~(W&AF>5gN-XWz*N520YLlWcR=Z z5RhpYIBFp6k<}|_+5yhXa4BLck8&B!+wEVR4!PFzDN zw7a;0)@qc$8-!W%B(%Hy&NovxD0lrGInz)GZ$bx=)p-bS%1fHD9HO1L-dbv}68~86 zoZ_=pP=1U@Hq&Y3%kbV>8m}6Ed5E0SvnNn~)JJ$z1|%p@H!83EuW0V^4VbV^&@Uwo zsZdR@FDVVFFfLG?GOOdj9QsR3gE|x~+9RH6Et&@DCADcS1||4~+C6r_AZSnJ*#meA zRHxeNZ&+INM=;Y`R12t={00FOPPv`Cu{RBa^xj-bub^J100Gr|b5Pj;ucX(uUYLL$ zg?q68r5%Rk*W}(SP+Ntty$dPMsjb8? z^D5x%Qh|0JNy;{oOxR?dSXlVVq=zCs+C21ibfAs{2S+E;fR%flBQ%>nwWpCUSm6Z5 zePc^uWgqVQ2OqNHtQ5+z1LyI2&e~I12@B*y02Ww#Nx@y`MDls#$AzJGek4NaJUi#t z;6M0*dA?~$H9v~X)F zM_QOhy=>3wb_iXTj{I$L)k=V6i}-nQjT@{fEP-A=a(TbdRS{ndr#N4%?Zpm8xuPH> zGs{*_pX1KNs$_6(hgmm#HVp#bs`N(~dF^zfzNlei>1K5fbZ%o;TjJmI=mZ>Vzpeom zIalH|Gb?9W{wPyhYX3lIL?k%eDA`AC2v*>GM)%A`L-9Pf^o&8vF-yXsK zmPhvm=F!Ea-QvW#h4cM^Rt7pBqtINVU)q^v!FqhfQ10FzdGuevJbJdEJfZ&19DdJ7 z9zEzIk3M&F^SrsM;0DP@{q1S}SmXe*{q;nLYa?LFOslB1t64d@)>{TdrxTT|LSc)L zE+~(7=Qo_kdZxHCqwd?M{i3P5`Q%s|_SuW3j!v|qN#VBdND-779rL0T`M?F1*HVZM z9z^}nis|3{wz9o@(B+XQg+DPN`6yhuU77e~W%1F)MQu#geN|o;1DZRsH=lgqn-u_? z_@&$t>m=biQ84H0*sJ)K5+Vt&@O?HJc5It_1*AO|gRwDee z=nAT@aVM7p*3lEoZAfwC$t;0&bZ>pq#OPu-1aj;av4VBxauZ>bCS_q7$5d)UARSTw z4WvW5Gx#{ogyfkyzF!E?9{`$9n2Vi`Evl$$#yC&k3Ft3hHbTjngdmvE*5h4C&x zJf!Rc57}Lr%6HF@w(3nhDd%hV=>UdtR!`57$q#$dl!^!4K$v=R-JwdSKPlbrULxQ_m zgu%N&ARjV}!kYfmsQdE?o2db`z__WA<(3@nzA;m^7m5;Nv&^*{2*czi9VHtGU)_t9EFIlh`Y!K&3wF=sEeoI=cH- zr3-ax@$#Sr8~G(xSjn6UiK{Ki?8`6Iwysz?DQ4`_-XJDw>4jdYMLm)E+k*m4uuAvJ zMoaGU&vHMTyqy1#1uRBX^83jhrxh79VQcrd(k0}vFs3_C4}3cye#*}J!8P>fkC9c% zT7ROQY1SAOfh)#Q;LoNPFLI&&QUd;fRS+<9AarAl{LeZ%`O#l>^zDL@!q%sVdVPBJ zK)IpNY#RF>7$EYneUpl#9Y0vC0mWIRlIbiMPZR$)~sZm zyd{W-5-rp!I^ai9p#)4d7^+-P) z!X0Pj0`gf_B<$|CH7*zWq~{an$=i6}P&L_{q8}vM1|q`ZHhYTzeL;^{HzvKB^Stxl z_z;Y`dCe01JJ^y9gpj*PyO4rRapR;}Wq%r~B~=9&b>}LnjKn{CC{yBG$?(|-C)Nki$#pu8KcdwpGzbB-2!>Avk(ya-GD8**{E_f%GFiah6 z6&}^2G-btg!ZpS+_6T6bqWNN)k2}p7;Aj;87a&6V7a(HNs32!pW13@yF={z6pKhKe zG-Z-A$h%IP;+%HKJk28g%lm-)z_U?>-av1pbA6TQLCHP(IXgXW3T37EDV53n0C(&HVmvWj-jIJWix>!qn7uV< z(vSdq=!FL=KtRM82#Ab+03zSHbnQ&HhO!vVM+6T@oyW4MLeu1p26eE=e9KtLoO2#BNr z0THDSKqL(ah$I35ksKf(;`9NCr1@FZ#QhBrxp9Aj{UAmxYm$15y2GE$oRgc<9+fBEXIXZbD$FfOo*sr6HZsH{?;T(9xDbf6H7@kp==Hl4Xt7GO9)c2+1~xN(mX*r34j?x&RTa9a1d&fJ`6{GD(X10f#i@MFaEb2p@TL zNnjqG7??-T{I5K^jFNR91`rMzkSNh){0hvY+kWKH6aFiYE(y$|2LbcwB>z9mqi_7T zJi0I!FpvI&Q$xfKPo>xF3nCvQa*Ggp)K|8%z|lG!D?>z?ARk7s`+i!^PtHf`tGs_q zRm6MbFlHEnMbR2TmU~fbLQGe{XdGy&29PzPI}GS90C(RZ*?;mo{PcC$1-aZ2v=|cJ zX-@7n(}r(aJ?XR82BTQfBC z%%SF$Fw0&59FtROM@SrA=d3JL8rOP9Nt{OK;wWDqhy7JoKge2h`EQN~;>Il4`u{DD z{{Li=Q)BweBPVF)V(KLC@KMS8`%-eTnyosHDw1zXrwz(nikL)xw*nH4q(2#5Q?Vdv zXHy{S!e>RT<}FfKTHU|)#d>qfLilw@0&u`mc)khg-TrP?06aq1jz-7aQg| z>DlRxe+!Kc)gudkiDVMFa!gW_*4fxAAT&fq|8qOB=gX06i8ldE{M z&O5uKTn;#yG~(lPN#aJJ?v3U?R=9oH)R=!rvf5H(Q-6)R&WfhSqJ&}jTXmK`KO~2_OG?w4qN1@mf`_`Bs{;Nm zlX@Py!}`)Cjp`&i?%3v9O(Kgw#i8a131Tec!I3^bv(uhUpEn+?HOHR)B%|hN_5dZG zlZtvFNKnu$6kmT4@>H>{&_teW`_n~z2Dd^vBF~Z?!bADy>2<^$TqzduT^!tWUWrfJ ziUr#(7_(XQxAkcUO3j~W)gGpJYg=j$I__KQaG{j9@PgY@w6B4f7^Izo9qcZ1?Ujb| z`)ccMBw`5>3BNLno&vT6J>5zWXH%wd3FGj&zcTW9`_I4zykm@#3XyITjq6=|LLAPD zyT7_;Hd#LKXWxSw?O*TGOclviafW`{1m^>pu4pt{)NDK{QBJia$iCmxU31QXIsfiT z`N{%19Rfmufiaduh~fs%OH4oVX{*qUCtIiZ&?mEVP9TTDst%cLo!2TtZy}D9%PL*Q zoww_FA{GkbfyIxgGgO58hT=zP+yfz`pAci6zO=ne+O~gG<`46^E!4a9JEuCiyAP438y41vBm=Wu*IgbkteIb>@PgEdT0%j+(> zpI)0k{h{*LWAH~>tATpkL#scv%a97wmjn2UyU_J!V=M=5XkU>TJ;Q@cE<+^U>dfRq z*?CwDueyid582TEF(HY7-ngfK2tOg+v=6J54CQ>#$s+(m$>g#;rl$1Ati=$s9(077GaQVW*T zF{R*A3Iym2>*m41$>d`BqV``zXGm%ZXd-&Kd{gf*|J~L8{_-%q{fT`xj3jCk9OgTL zFg?Hsbh&<5>`+2-$UD#>cN7c@Hp&z$G78a@mWe;1enKO@{>P)n5OpCDNxw#N{m>&R zpq6ytbTII0p$xk{cv5Qo++ynnbJ+I5>wLhes^(aGx~XRWDdYVo&-gqx4q1mS`qT;C zeED<9_Du^ZsYtYuD8m<&A#f@jvM%?$-;xU8+w(N-d53MD)oRsU(R{PfT@CdNL}W+# zeFkV3>JoEB4#{Ka*{t}ybgGEakr}3iie*XRVp9{}rW5ki>)gC%poP~ZG zVU2MwoT6O#vi$N^RNPKulnRI8n&%VN~FLry<1k-2Ju@ zcfJs@&b$uaXziSur@F$#13qiJUjK>*y$S+94#vuQr2MYEzBg}_%ehb>Z3;vii&a+L zrqhGVZR}=JimdsDTY1#_?`=@j9B@-z)@y|E_))+JGIQ)*{f?TNl^gFiobe_*CFbx^ z>@N!xsXRIs5lWy<+n(Qw0qygrHi*ssJU>-By6nb(rUkD)BrdhZ2hzTmazU`oAb0SI zut1!0DqKP%paXSVPvt za@8sFg|>QI?MCajoz;TkzpYgN*qO})jIw>>IO1-T!(2JC%LoArh6SPj{2gt_$)5(K z=5rdfLo_lq14LZL-W?gfAg;#-I3AJ_P4ElppE%$C5u9LOa`Ih_)v~bBq#gvik)9yr zUD>kTm)~KXf@wG6HNX61)VQX9e10h5JO|gTx%@*Sk$C&i}~dzc&2NaE%0g-;JdK;EjQXgk zN)Cpb?8t?>LJpRnX4Z9Z_i_@`ey#X{+OIo8Ge;%3w>lb*fUv&%Mz zu}|4u$;PlsS32=B9LQ4*a-4I`8_e8zWcB3yl0Q4UWMrp5(>0mpH8k%J((WNvIi^U0 z_#ycwa*{qFzW}@d{kOkZtqENfy&9m)&jeV*`9EtkmH!j2X%(2`hCMT<*@ z%rp6;q-NwvOFql(zqKB8pU31DJx^xmTklC8kzb&?FCRBDx%h1NqYrx{58vPU9?}o# z+Y%jKb1Qqmj`{|zz!hMOq0NOjk$*US>E|5p=iHu+@{KY~+I6(cHTYue zp0Hl}We6+h;2sM=0ypjSj4K?q>tUyF5XRCua_#|u2BZS9FQUFnnATcmQY^i_dsjdq zoV~*{c|U2t_D1()9#d!kc?X;_+;7Kc{(jbe$PGOM2`2B6b8$EpI0ENq=ziM%(hc9C zIJ3vBb%rl7Ox~mC>O|gjL`d>EXDM-ESWh|&Tt46UGX+p}8EqTOI?TwmSn)Vca_G|J zT;`gXOU|`!Qqr;N8_WuRVMy6Eq;bd$Q*a}tv=o0fn(tp=@$g=B!$o7^K_Oo!sodsc zOq-r*IWbPLl}mDRHglB99akbJEs>p&W?XykI2@^95Q*N0=gXXn#K_&&7wKJcChg-N zZ`tsLKBu8IwFz0gg5Aw&IGU+ov+i5kREl3?t!+Z4Hnr=PLCIJnq4DXhP9$5CoRZOu z5rxI6JMXOQXmZFfY~_sb*mRuy=|qpCyAVAuw-s{&3_k7+Q2AypMBHI%`f((mdw+W^ zfet-asQt#s%zv4Mc;1MTSJNhbVq820pT&VG+FsN3d_-24QIyR#qh-5qa3kNm^#Su~!^;!A zp?&|M`ax%FEh*bl{WL4A5YA;T<&ojjs0qjF@E9gG`i<-8ytPKmE9w>N*|~ous769J z=8fyL;^;iFW}&;-E9=&Id8M&tq*d_n8CZVpg_WdQkX3e1V75c3F*xyeFt0d&!5$Ws zFF`zm7$e0n#uE1E%j3H|VZA=<>@9S8HDT{LwM`j2<@h1hIOsFfl_J)nC)hJ|x7_!ozyNSid3~32l;{`5WKTSr=-xYw73tm zg+)Sm%Vy?Bc`{Pei5hZ(Z89W@8y*q&*I_+64Y1{+WgWcDe!Dg&?qZ&Ds#)H_(Xhv} zv(SnyFE&TlXungN1~yUv7M<2 zV6Ch`{kz;Q`Jd$WzxFHsWbl7feE+4>_~(6sDiuq|bzv0VbFsux3!R|EJBvIZoRTUe zf#;en%FJIZ%JGmV7$Rfh{gucVW_RO94bU=EWqDG zjaNL4RD)3XRP&AAiR7EPD#LoW(lzX~7}t?#xrIiFJCz);2r{}=k-Hs0Z!ydu>jB1& z9NrEjD-7Cn)Gh+A(UnG;qHHct!ry~|=r${)4wZ(IkvX`9ze&dAD+2JXnDcb^-ynb6 zFEu^8+4J8NPG!hGF|9V-)e@k*B527?$3>^>|0o%0!9a4aAz{%L3xD)*7JGT-1fW}W z9>X^__qq!%%^31raG@+GmvCE1yvl#Y7b+ZTI*o)Mm^pO;zQmfDOK1?)6=i<*>}a(uf2*GB^5Oer z8_M9>vB|1GJqCvd0rtTVp5UWAua@$D`wg_xRFbTwZ)~2hyW%KuA&uCs5^%~6C5L%! z1`)D;I$df6yJ0-)+B`d4T<^gg#+ywdm_@{x3RZK49{i-&dWXNo-dK!jlPxDIg?jqB z=ay0|j-F|E0p3R6CB`HxhSYEaM~A6aUmJ-E4T52W!KK6P>Rv0g-V)rxV4&Z$dlweW zTFHFCC7}(zrI&ggQj76b4xg;i-Ix=nV8?Amm2BxSqxLjsz?L%}OJBtc`ysoa9B^?(m{!Q%7mdxSpz z!aU)*cKtF!3Hgq}5k%c2^k5EQoO{^86QW0UpBoZzr`RO}(juLrXXq7c1ZZ32v-zNf zS2Vnx$OIDp?mh$;J`#vRTG;W4cXT&CvoFi;3{O;1<#f%`JC~!)lJ09+1i|Cl&iWp#pLHxI!)= zaed4wALKzC5LiNWg}=3wuI$FMgkFr5#T;wCkYsqpzr@=#Id$}_=KY?k1*XJ$P5;$` zw}Y((Cxt{DRdhpmdg%DMsdxRC*sDvB!h-v=|4Ild8CIKIQNEp4HSDaWk2?IWvPud|hF!W>%)L@z}vYHVe zikg9sHbI}4lwR6v^SAg{SfGek8Gn>}P2iNYZ8UM_9%4P_9_mVn^5!xEX3P6fn;Tc*mQSYpo&cY(W7HLc`Z7Fm>Cu}D?Sd6dmXvf+1XSO`Z= zEjcW7>Xx%DeQ#eZwO)=Wf`OH_fWWFtO_DKTX~bA<g^E_CPNlkv)qu2mXhdjE zv!G=y!8{-Xy#+<=;<6lFv|m<5sd2@fG!_3fP0jU+doEm2J7R6hqpf{-=2?7N+(<@q zVDfSEmkQ8QXLz!k89khtL7T% z#c)~DGRVXF6^LQr8W&4Sxb!7JV&q4p@Wn8qfI8>_*iY73a+UsE}4afh4wNf z7E8_IJWnI165R^^E_LfUG@+FN0^JGiqGdsb}SKN|0nkC)sQsI@Xy)Mxz zEaz-g5%e*~j|Vdmq#L^h9-#NFD1E?UnTBzOVZ?oPlW_;N911uoobxzr zVj;v6ar>?P_DRGu_EGy>Be2mKI4vAdI4ztw(WucxBUEPBE&RVX%m>h@n=DTE>HVAP zb*R`*%Ve#5y$w)H=2ADz@p<^EwO2Y8q`1>N+`{=b$UY^w?do!J5WZ>MU_7^;*pC_Z z@7IqMicJ`f?;FRM$25;bj#Q3hj!@&(cuabB9^JN&VB^_(bRO32+%}7i?1zu!k0_Io z^kDn(_1faOLkm(E;$mIJ;S$~T)Iwj@{Jbah@+Df3&x0vt6nMlg^>{R`70ZH^`u%fz z_KxsFtLM1w4a?Z50;LHYFUAMD9D|$h0SMS|-&f$K%ha)Pfx>JPsNAwh zH{|%Nh%vh^?jb3ff&FHz z3j1+N9!&SwNY6k{NlMvIpF{9O{6*qB zfHT)P{JHgA?H%!W%-Q8#=^c6^{sQ*_<00|5n6q{?6~3a6)^*}YQjR=dwG?OdN8w%R z7HPq_u9A=Bb#h5!PvJ-77O@;Pe}R|abrSNpu8NP!b%JS9PyR<{w`#VckIrl17Cm{A z9A!@~{3!HzNz%+opo8eE$YBT{3G89RxZzuEBxTOR^Jn1ni`HAv@h9D94AJ&p{^m5e z)`<(>iQt<1ZvOi8xl?({x8o?_l8*1bX90>Rfj3 zY&KD`w=m#;)WXjnEJxk_`d9xmAB`+m86dV){wMC%|JOt8UksD}xeP7>tkwQs%K|^- z#ln~e5lzE%h_y})MT*#BdqF=v;J+LTEHw$F@OZ_|_#fy=nL(Mxq zcjzKI6;=2{8}m8HRASg0a{?x?Tm3lOb`cu}FxZde6@vF#m{-N>KK&VzR1%x7-UQ2U z$0^h-H7b1oa4jeYIO{Z4ysB#?(=Ck-KpO+IjTVU?QQW_|0v?&2jxQb?mHMOsp=3Nv$jwa{L4jZvgMQ|DZO zS-4H=xwS>_kYfO0qc_|rPpn3wUqnrc z70uUJbUCtCGDQ-eA*k|U@wjTq2c0sUTyn=Qa4=Ues-u8f()7t8h!dQH2f=6mh5{F>%MLXGultDDc zWs;0{mb;#QPY4VA2R^bXFY(t7fmjD%3;fnPu9=?E&|HD1P zv7(1%>`7NJN|^PJ!K6Mied}H3yK+P%zLC~h`tJS}`($N}tlV2Kn>&QSPqZ4%!<8)`*>Jnaiu!M-sT+csI%6{3gK591#2c0MzAv0x zqf$&kq4dAf6&5&`5IfI8{+Ql^bZUg-TKhfs+ASi+9T&YQa4eU9zXJGc>a_CPZ_M4P z;Bk;)9m5yiwo4aAw&0%8KbEs*9k0k}Y8kD@S7AW=j`!VbnWF|<0C6%rQ9 zB)cZ9G-3DyFJ3=`3GXIn?-$TaZjFB?gBD>8qc>_-M>rFow*0w{zjCoTBLL*+wYqKZK*=36uQrI%NIPlnJ(r+LQqom-tnw=dy|~58Qxo3E#r~&x+p$Nik;teBSqqq73!^l2Q5)cui6KYVqiZr1&n0zU9NP-v@OxcnUGuU6L zXU@uv8KnSo?70UbYN?w#ZIho!`K#8>s>)Q&#njLMUoKeXoOpyu%Zv~U)p6;54Uhz< zDIJxD3#VqiD~jcYPuR^5z`)=@sY(4iCG&*J#V1lj;^D4zQR!;LBvo3-&{6B}vW^G2 zMwn((`otf4&3QEu2BvIQDlR$=pms{M^UdGf71*RItt@$9RxCPsRHTeJTs%gSN-Bnn z<69=u>o}Dg8fv?zpqlM=wv!mr%uq&uukLrhCzHCFP7&=lvIHJdai3Rq7FM4( zB9EnmDeJ0CVCi;b=y*yIBNEGmX1)x|fy5_4zqu0sN^ze^aj&D*MuT_KOIUT3-5Wvn zj#AXMcC%}P+-_52w6YGRwM-V>oxun(uMo@v6(O)KMU&WCpG&fCx|w8x6{*6aj4``B zy64M#by4mTbj2WYZcC6H&mt~3)VOP~1xyD<>jqbEo~n>w7q<4QNFAQk`jB7P(JEt;JI6Ls zNX6q^6lG2Al}H2L4Q~_1v)1+}+|YEZPmcjNWZT=_3WjQ8B+*ECT(>}^F7;UkQARRD z+DMc)(#DmPn8=y|K>8~{5Jg1keAYai!nB=bSGkuU43so!OyWi^5$oAS$S^oFQ84*+M1Ol7sny!&BE4}*`7!@Y!;cYoBYF$xT7^gKBqt- z2OicL#rYX|f7}QM1g)4ag-}cxvYvBHQFfJ|%LbVhk`&%ruf1kx>v)JJjF?FkNAE~H z;rC_Wa0FZj_xgqob9k|A5lrCSc_7#1rQF!;YOl#~T^B%a`lWJuy+ksbBQsC;2|*B0 z$5^6PX$)1UWI3HNT;?rg9E=dVQ8n%@cOS^z@SuOqOx3k|f+o@*=_TFs+vvCU(8)`9 zK1rw@tqAH4Dc$l|+;#k(@L0;|A&)pe`W@P+|Ivw5k-zttSNaq3HxSVn0B3G+pQqK+@X@WtG} z!T#i0sH}Wc2teyI93US0-^W`2(Q?h7uIHc4_5Zu<>n`tL>HKB{Vnx&sRDWy zfF)m9$21aHc_`X^vpj-g38~h^2sD2kie#yXLKP?rUJ2O+^AcubCV{iS-~Hgf{JL+x z(B;u+w?8c5AKq~@3rQ^e7;>6xa;SdydS8FP=$d(`>G6HV?KN+u9JFT+M&XljaFSvN z+myzBk-nZPyy3JdVTf4&dR1tLu3LCR+Rem}(huil{SB&++)A^pAh}XSS-BUZEKNnd z?Q1yjrQ?1vZB+m{_4qdly_M95gVudIDS9m$MGIk-r8EIw0Ro)|Q{b!>^h58omO||@ zbbxs+wGeRG9hYBk(>bXrr>?d}R!gSs9jXZ4yy9VJMY+zFruO%xk5+TaDo5!wV`I;w zk29Go2NK?eI^BB02OV{~3=d@uc5PFUw(K(4HPqQs_u`};LRE@Xnp9Lx57rbbIol21 zo;1hJaV7ijNu7DngFkZEtrt27c8t<-R{0vRMxUo3gvGMz=Uvj8(<^DwlelRklIP)E zCFj%Qs>_ad4Hh*SPJ?$o7}ekR*5Q4 zS&CF=HJ_-p=Jxk_qq$yZps&bwz^BoC6;anH=W@}hhCZxu!27yRHD~Z#q+B56B7du< zox7cTcM0?8k|pAJPw1hwSs@V-)WMX&JLekOh+`|zhRw{hL8f|SZ5|d4OYex^2G2fK zxJj?2mLg?}z0#a1Fw%0gsqgt1en&At9AbOYNX(FI&Y9h0hy-2Vj!>vbvcTR4HUlZH zsLn_c1gu!Ky%pDvBq8MEQ6N%ad`JFaW#MV3#ZKRq^v#yZ!64Oa8AqaYD7Ir2*A{RZfNg$65cHcpLlZvhoR8QvSQyr92 z@!m5cv};^#_<3Qd*LkQ)N|W?iv+rH3lDU2J4K$0(m-B3q^5S{Y0HSlm9@~Rrsn{{g znqIZr5Z}0my(6UA>WY$R^;gLc6Yy-Jr@;~K$!2WEX5K`eA0#tZ2dlgroc&8yc6itO z6gx4EKD#k2fo#5ooWeIiBd2!PUv7yAD_~aMexTTmI~E%otmYuPUqG87+50k{Q^S5U z$eYLUz0^8Aw#}9Nth^LnjYP8+=6>AXyt%@mA0tjU4$2(7Y4hk#9p!CXar7 z^MV}~!kEKHjN;L7)gDLZhXy(J(%$U5b#{H+LHP>lvv!Qa*iL8OZt6xo1(G0tqIoEa5PY276g@qub zIgs!7eIZ(D$KcIuXoq1BAuINrBy_{~s;V2D%NQ&etQzK0ZY4rH{}wu|&Rd*QQCls` zy(kj8ctN`tgsM5;G2J>tl}i0%L;O$DUL|mhoq@a;T&5NMoYA8<@MVH*meTXPCD^Y_ z=U3u-Brv~0MF(!=^d{kbdE2G23vhIA=lE`GBs!b~#WMPxH+o4P3L+?-085u6bg&z7 zJ3Z_67i1pf@4UAp2^7(EPn#Fdbv;nQmMKqvTY+p}ms4W~Wa&-#f0w2ILjahtv6HQ( zvCUsrg8$tPph@++Dz*s9uVfM$NKL5);Cz)*18gL{ykm91JWx%9rqb2b-)Yw`L--N7*r!}rLMFu)gI?cW_9wptwtb+ zM$;wE)9Ls&;2d?##l|I&*T6(wt(mijmS#oYMMa3mHVKDp9B-xfyfspJ)r3|zatdvO zc42!%yL>UN_aiG~@kf{)Pqpip;h0`ZWNmr}xu(<<{LLlTSDpVAT1= zciXY0jhtre%}Ke`(<%d}2Cq3t%jzg`vh#+fB(bV~vc~2nKprT4gk}V3AB(Q|tgJe0 zp{0kzH2P><8Ay0dA#OQhK%ft2$cEwyWqM`~KgP^nT=*zKXP4Wc18Z=ZpxEo78` zk@#c#T0qD>$z3wBRqZEzS+tVwXFk=E_6xscnPuJugk=Q1dbbGVBxf{rDva2Jba2nG zS6|nNW^-E~R7UrCYUQ5MR*}0}0Cy0Y=imj?r6BX~=1HpnGdWxt;cXBHr=fPMnu9rG z*pj;dqVGBbyqATUhi57uX+rK$7Cw#3E*ItaT-jTh4UVDEcX?t?q)u~7cDze^j1x|c zmCU}pC%NL~wjnV6u%!wO*XLzu-{MrCV@h#2Sy0;9c@8104>`QI^b+-zUu0rJ4;W}d zC$OqnVMKWoT_<$>x0{XZot7N269-vg@N9)lGXu2g?keH-%0ii8iOD_MUGalorlw}9 z4#@6Xj!vfHy}=~oAe${XhcsHvuN=9StQ3Ug*>xRFVV(A5IK6CgVNGE&g}A%Wuz*?h z48%v!ztZi+hcvI@&DUA&0O6gz%=fCkXbeQH5Ye00$n&$SQE+w7*%ignD#?f!#qz8n zIUOirCRuTXxFDh*ek@L1Wx5dg8&=65Q6o0x1EQOT zeZLZj{m1# zT}c+y$piETj{m7Q`9JAP|53fF!l+9UhSZ@8?ZIhYs|P9NDm9#1qB9{E~|*qfH8WouVcD*9RO26H~vC(F2Vg0M_=pi8O1r{56yOweDOo+#!}>!_%jQfw9CijyLSxMIu{III z%?FUvOEhc4g-PqzYQxkdf_=VKQ-XY%X$O(jpJGI#>YkExiXy54`kL0&uwR6v2u+;q5|{W%(3nR z2|jwDp6m1M$)V`R(~oxzObjtt%lL#yeap@>v`{=!Y~e|GX221x*j9k&HMR+1t%6*Z zjD88eE>1cM?d)m^d1QbD5}&Dx=TiP1Wr?V)SHls$9y;{KYZ>%xj)Baa7l_lE(fZ^@aoBb)Xb zC!RDcS_95t>abF3%d>$}SWa3h?vSd}@H zA5;uJvLX;pStwXp!>~1wmuG92Quzr(mwGX9N=Vw9Ij~g(fs=Fe5&@G|5BPcQ=UxO! z@LNXpF1ne(>gDh1ZlN*kFKtFq`ftZ)WKoR-!|h)_+hb9M@U=aXKJl~*VcJtJsaqvy z*gSp%@ve^vArYSo)#D+h=N>;U5*n1Lnz@H9-w|hf1U4@TQP9u*A{u=CamBUg=^Yz_6E)^ z0Mv(Ai+ONy;+{wvkCgFSX#lF+ZR9TkK~;so$zSe2iM}ccwTL9LSM(-Ar6M)i*9vCy zdMAncV6s(*0(zdC5BhrI^Gsf-#lN|zu4EH+WMI4dgIiz>lwoiz+BJv1RWZmz9%t0z zbop@JraQQlW^O8u&smPoNx<4pU~;NQ`zS?6+m4N#Hjs~(8Q(;XzkVh*lT-$M5Y`B$5&eo3fAb{&RI0WFWF8~zAUqAo*b)57)3dp}7n_HbYWUs%QY|jLzG{`}>W- zNbDmqt1wSPRaEuu^%^MVybFXS$;d?IynmND)>Z|FG%?`sJbubN&V0_?{QNwAr~eWm z{_Hmr5ZdSo3=DkbxibXf!ebOCM&w15%u^_u_Ng}b9F^l;a#I9j|!atDoI?HJG} zeX$+MvpFA4lN6vmTq>VFxy0(sOO|LYXwS=-zzMLXDq2UGQ7nHIEunscq(xEl0;KCjh zHod{AAkokCW&nbutaL~{Elv-T;7PKBwnVDdi{wkqm$iJ!MQxchAqWH|eX&dH4yspK zG}qP4$|Z(57uy&eOg#Fh!(y@z8DWDuP@oT+d$K>C^bQq=7V$Zk#FHD= zPItdO@G*Hk#~m|C1Scea7$tVkm(at+rwlSijjphXY_!Qn6U%%}{k&+EZm>EP5TE)FXzKM&LNuU%S zvoxV(%8o;+WKNn7lJ(VZHT7fcvo%)jSQrXyo3Jp{Vmoj%uKNw;w-^MNxp1b01d`15 zKNZtPaHY0B|Ki=n=$qqy01j6pVD$OFpDluadA6i&O{I-pjII9G>1!EB1J5iyII9I?qsek z7Os5X&E|Ey=5;hV`t|a9$nEEhQV?q|H^Afor2wVEG8lKPuRK&JI;N~+uRFvt!iowR zeNGjRgI}7u`y$^*{IyJ@jA0TJwkPSl)7y9F?b@Mv#nRa!WSixJc%7CZXrf7@X_%mg zX2}Jj*_BFJ!&}9t{XJ74ZJQdi!#H90tYVidj(Fm76*t6*>^(=peZtq8ITAD4^!h>L z-Q_*F>3Tk#h@~7Hh8lB!maE>O`jFMpq~+3WO38D-b(V_nqlRFiF5+$&1QM_%* zei1(KIpkB4+!h|K{_BJiH|92o@X?kO*Br%Za=$rRLi#lIh_Fv6J`_`$F;d4#v}VoD zJH{nz+z4Dt^%?$BG$peNerq7v(wQrGLT5MMLZ4X<1ij=m%4*ty{>!eDU)YxfplLfC zxmy4gC6c0A4~|89&<5#F?mW<2@C0UF%m8MkwRu!RDQEaG*9Vrcu6*clXa*uj;OH?A z`jMUD>{z+bSL)z&p28uRM_D{*d~be(l4wL|4RvF8xsJesNj|Q~&E^0EH^_IYCidK3 zge%x1pp+n;X7mSvhgxhZK>?z`Fes)fXqtQvV!|7Xy>nX(Vgue4vB@&AcVwD#Q4Hig z=*7!SRpBT_&k#ocp0B@EbzBpYIy{&PdL7Bl)nCrudDI&*Mu3Pl0z6ax_lPC^mk}$Y z?`R3|p9K`ZX0}Fu3)?6~OSuJk3?I15gmuwqCn2cIB&g)C}oM(qMeqY~@ueE;1kU!jV^`I7z=8>Gh zy4*%%F!9oo;^G-gV!386!7$S!#k9O>b|C{h4QOh*bynR*7);cBlxy(4)|@}#+b>zm zoxL|J@i}yiH{qT>vUmbp4Xmu09+c?cFj)+@d03oR9;iGROTP!z&I_Bb{?wpmitM@e zx_&qb3})~dkz-*Mcw72>;Cm&F%s7E~8?g zK%l-)@>+ls=qAuX)bll+$}R zReZT5bU2gWflnPQ$Dje8A5JjOTvAsN;>q^-X)1SQ?yt=6$a~FX&>DLvRxV6{&afIesqfec2^fXEbrlrkls zrq04>j6&n0T@M{{{fhwe?;&otwG#5>3gltH-DB%M^H}TcX=WS02WWE7{0mZX!01kO zBq8R4z{4IM`?I@|s6QG>=HWC57-KX%>L4edLhKG;%??M%tm)ow z+1%&ndi^;*bMZnoEAvEglQ|cyrKRmqy-b&J0n~BWsM5fG!Dhe{Mt4?+e2*>?6UZ2T%d2Sud3}3iRI64$*E%LkG5Vk zY>`rLENR`0P1hZja@Ysq5kX6&>8&_ly4I zP-_HaG)j?#-wDDt#48`D9oT?gtK=4};4e^az3m;&fM;fR7-B8W!OlVaA=VUrkQfeF z3xzjsFR@sTZO0Jbtjf0-kv9+`*$9#e)NEv-y~u~b8^Vv%v6|RtIhKADFu}s2_)A0$ z$Z-21O#{4N!{m1cT1K12lAq%3pT-dG#=39N2lrJXa!p5$hbV=yE(!c|l)hWPf|TY^ zYKn1)?EG@=gyPYVs;M^ca+ZlVYVC-9Xo)sTKO($rL+LC;&b}>Ccf<923~dW2@qbz8 zSGN^ZNQ=6Wcjp{8R0(XE$k80gi#$zdZ*3I=@Q*j1C=4^bL(= z^{xNz_Zp@2u7K_Qr@`CN69g7dTZHDB=Vy&X2jp=JOavi?9R_JE#G*7rsy-iVtmxQh zj^8JCLusW^RZy_d;|;q#aGQzGP1~48`D!@xI(^99viWhpjqeN63QHf(uxvQGD+TMy za$wl%56sW@(@~dzvKEtg$v_K59NMZ*11S~ZC48v{j0|kN(gs=@l1C5V^<(aDtNtlV zKwLX;_6*Dn%vR9>+yIQKQUUA;3|HZaWdXHlwZ+690ablS^*A7XzjK?d`kQh8<#ND; z?7Ss&I9uEP?kSJChM?I34f@=Kufv)OVw06pW^+wVn+{1ybt-dA^59o;o4N{tPUus$ zvE$M7vS@W}ClztT5!4}B{VUSYMJ39eJChN#JDB&?SUObXMz^<-DbIS1aiz+@qvc{K zn~uh`by{-39Jr~OCU1RL^MVpXwsaOLU#CKi!l{4eIrr<+ZuJ7iS_hswi-gioMLX_S z7u_;udF(cip(ja~0pnpmwu_1HOJFOmnh{X(+M^BHfQL)d<7`nMVDx`~snQ|9a@^4* znx`>kj(hFIkapIrTql1U04FFh-Re#>UTBZD#koV&L!#2PS;}Ea7h{rnC&!#4s|(`& z#np)?sAA`go5Ok1P7 z*_yw6jn+Y0QpuSobPlCp6yCbzR&9g@!H{@6RNLm1o^jAw0msnqX#59|zJl6L}f`ek$eF`J~CLrhGcl|hsgFTsrm zkCiX>#e?SwU0o3OLF3R4{8NQ1Gl*+ht2p6>m|ztLrSo!#K+x^S>^ zUBmxnW6P9#-p6eA=E(iH^+;h0po+!YnZ2ruR)kTgM6>@i;lxpB}c^AG_salc-A z9|&d_3?5Tz+>Q7*_e`0YN&Xq*>?6==ll!7a;lrun34>Gb{@U{Mq`~~U;$!OuqeHeW zED50BS{fNs(tsgx+UbKrve})12^DXep=s_1yOv(1Y?YpxsCr9OlkjTkPsohLr!Z5B z6}()U`5gzYj>I|8X071EuhmFfNPc66PPS27`?RmOF3Lm^T;?dp7==ce#x(W<*$k1It55KwQsz<5ieI?85!hF_StZ6FoT!YG z6(>S~wEo1Cd?PHv{`N{T-GPUyAELh{;)cGfO@Hk%M?9_Su7&35Nf zznhjxbCv|KUJ}x%k?fRjAdgsI-8w;Q#rWiRTv(07v%f(mez=32d!OP*JR$=!8mNwH zZBC&L*wD%4?Z4Om3d|AMklO;B=Vabm{Qy?6v}&x~x#2{b_pMwkmel!A)%2MpB@7u-ymgo*F)@XssTW9u;Xm9Rszm961K2aa5j#19W^0}aBy6$1G+*bfgOd{ z2L$cqRS0D=nt8Li&4NJMYiNTU27vw>l(1ZD8e9ApqIN47?MxU1d8bh!q zNAKbTP8|II*NL-tHg5udsv?}ObTAttgbjRFu&ScE0dSiHp|ZSG%HP3F^EsR3U;TOo>b)| zF`ETz8*YnhhIC~uXFQg7$)Mc{o0rvQuVC(7)72F;+N!biF~o`Mh|(Wr$|Mjfm98CS zs8|nFqDR3-m>8{?IY;R8-TG>eNvT z&&?mnCSgIJELpFcHJ=$V|Eyw(r;<4iViZOivl%HjqE1!~h~1GgnJK+nlzZxjLmwq8 z<*xD=^3pl%GRJ*2zbY|E+-_q;jZibd=;>7y!I@Fo5R@H)sJ@xAMn!}v|8d7KIKTkU z2*dQ?oGh(cX~5a+-hH|hrQI+;nfac;Ibp`awCQ7ALR}T%@-8tpzX!t`2IOIMXAp@F zi6F|0b7%K+07J~Ila_#|eq=hyeI+l)aogC}L*6E`xyy>ZyM zy>Y&5tmcvxcLO{?$|hiWx3xe+f5y ztiMCnRZ<2N;}F{Y$d&RGt{N#Sm-777sF8Zt!isNf`x6m+XFZ1oLmeEe#xk z$%5g%A5gB^|5Lg8KWB4f|I4lIPjmV&9y4GF_xFB8io2JlSkuT%oRO!M?)u99&p#w) z1MY~1YZ)S`dRo=wNTZHAO@w-ybxEVKq=Q066sTZ9p*(qt#6K?x<;`r{i>ZSJCGzA? zJUh{I-_x%=Gi~3FsnjB3|rnNm&h4OPafq$tS0*CJN*9^a5+0gKd zfU?s>{6KE0;Fn#Rr`gd3))q0^4Ce*LL;9I-RpA#3)=YVhdh?^##aIsgrW9b!jSGy2 ze4@%m06;Zojr&OVA_E7GhX9X&jr<}3u;$K2|5*dD=7t6aPmF?e`@WM~F9fWE#8GLb)jI*~O4T9NOAU-X z9u46JVC%0Y0#MD-RG!U#D`3S*QxI-KdMc}oK(wCvP6H)h^&IG>+Ydcy8H#sxplc`|xz(9J(B|VLUftez;GWzIbO5#a2H3cVWJkzfSLI32pTI7s zUKjBPFulT41+X=6Pw~YN@Fj3h^#%JMi|+gjcCaJJzrf6s=&f3-w$L;P03tIzG6krQ z>gp#jG#J3e`xz7s@}v6?tr-n~V)mt&MQ|$upqSN&Zbrs+NNbgLKtmD5V^@4kK{}_Io1J@`nBdJl|x-<21iU@z!F3MCV$Cr_@ypPRT-*#!MOx-6{o ziK|Vn3~_4hvsJ-*I{G!pW)5p6BmY z;q_=LS9DJ8KR7qd#q%bhPCmb_cLX+$64@T#4)z~Ew758K2GQ@#pEHnO+(s{vhxX@H z=Z+LCbFJ>(0gR%;_i-RVHyb6D2^=L8Wrb-AotRM0_V|X4a%a{hE&)W@mWZd4^bT`a zQShvw2;geJjP?{6JyV9A@uV{1o#%(6#)>GaOlsx2c)N&(fpf)oQ;VX8+^l5=X^BO_ zFf*{T2gy>WY`yBf^CEwsl!^|;lu-y!%`6|=oZ!$@Zar85018&+vhUcPh{FsVTQE4rEFLOBN2!+bosjFrRtn=9NdJn|x%E9llPSyhe$Yh`A*%$vb^GB0l8 z4q}-wafedMM46EUp$8Onnq1S8bs^?y{`&%+$JY+xFvcWneeVG=tQ|W5K19h?mk0Ac zChB2iUOVm=s0b8?q8@_2_UCV1^#QRlTJJJ5k~w6F5oO7&mAJ^r*aO=z^8M8+h{uxA zE8d}?v&VScXw${H!O-})3$^rlrECl9#U?L`Wak{E9rH)n5~{kWJFLN#A zZ<`%2t#2*lNKwVZ@vC<6Gt#V83_H3vwi@n66ehhwoEhR6H?{Smz9enbm13ATKf+NT z$rZ}{?Od)YVBM5NpbE+kzD%V`V%?-drOqjNup~tr8M3gU`)UnE6r5r>!-x@|0)b@9 z=ap0D*<$k1zDp8!=U5dE!I zU7R=%Vl)g)pGF>xlW7?OTsfEw{Th|Yee zP~E{7+%KKgrCuCp5=NnApmkvh{_L%qJZ+9NGMe5A(D?Yge9xLZS?vafUJka$sd!l% zciX$C2lofDCPWFfZzf=fZ150uvFwYhn7$eus0r*HR zK`wm3aY{_hE8j*yjY4531AVbmXVB%cB-|L7kmTe`fUC(uLrw%qU{R?K%oiV%JWJ-!iE@R6FAodrudKj84oGf0WnpSCIWW7UPGemYX|-IWJO?^nn_lv|&y z_MrR=p6p<^{)qDc^94_qJR8s^oP8}@8foIMd4R4~u=bTco7et5`&zYBsQr8XwQC8p zsi*9LteU~bSM01(+hG2+V~L}wr~HAg+QG(G;*6>K%Gy`q>`hx>=G91kapHf#laH(> zm$mc0;K^SIfZOx1LSR7d4rsX=*{c)HQW! zRr}a7r_wc7IUZ<(V7OGV4LbOu7#>wmfP@=<^gSi!6J6^UN8knh7xXW9Wt2}XE9jM> zuejqcPMu?uBsY#jXjkW-{MYr8#}Tvp<;G{1g3f#+dyb7`PYN_{wzT}f~?lkn8+DOFmT+5D{5H$a`NG@r8RB7l+C z*R~v=yLI6nbS1RAj#YufXd~b_fWSNt;B9VuU(z`pX+v|<@<2ty4>lGbAd2mdFo62Y09Z=q_0<4^S0E`wHBLHwGjyr-QXF!M( z!yV^cDM0LY9&pU;KdehDFyTXRcMR})@%#$a?loi|Wneb=^G?>NfPzW~ah5mtTXiB7OBiIT9{r05uJQYBh5 z(#lpsJW?s(_@s*%E{U?OKSY&Hgb<~w!MpzzpB?oTpKX-L4f`r(u7yPM6`{@e6`}2x z0BHUp#XKF@D0QS0Po`zqNAMM#9i2qmu%nwegpnHIA_@x@~`mh@UQUf zuY~Q!9h9%|Y+dO&(>^m&8rrsO(_(Oq_^O5->BL10U9pDYz)Gnl?VrC)bHJD5t6F!o z6X7xNNLMZUVo0-S+d@nm!CMn->v!Z6=V{xrOe?{k;%ysu^b;>IHYE0%cKi~}VF`XX zYF+<`SP%4%_n_rO;fC_q9JEO1zpDl&ftuYDWrBm(!GYNZ2y@~`=Edm>rvy2eF=y@n#5d8Jxk1;M#_0 zzU!AB18Imr5ZLa4b+n6|9w%Y+oggTrg;>+HGGwSlysXtO5JHECb?wzK!j6KrIc9)) zonO;_9Z{|Yw65O`N_`DsfO;KS(~bwm#&*Q8x*KX~)yAm18<~BDqfgwM$F||A&-_h( z#h5T`{`}3b(pSK?k?_~WqsUGZVW{~V^3T<{z;!=3-dJKw#|7caLgY2PtUqU#VQvzH zAIWv6gdn(98qyqp|J}<0pAj}P`LaKO;QY_S#(!R0iT=0O*8dSG^gm6|zb1_19nH9A zhDQ4};a>yvBeX6iWIU0G2@Jhf)0+Wh^Nf(1#p;1`gE2)$oS5GqO2c=l-0if6S=sZ> zQ_i{0p4*?V9}kef#H!x<_T|61*Z(lo{bT$ssBL7>7sK<<;J~*C3F1&u+WKiyXMPN1 zjCxvQ%|X;7P2{@q{MI(@QA#tiC*qt##*A{!W)G9nW;0E~z0B1rw!O&a!VKxNoR&eN z2lps`!3p|iE>?{$|3{gsIzG^7BU3CHwPFqbl=X3*##WD65`pYI-hYb5wbUyj&ifCX1VH`vMdNsurSirAtGe1b%lEn zZ7vfv)xxqR*Wn}O+Y)V(Lm6O+J%e+&3(?kza;0SXqfQRQ?eRlJ`PwA+Y;Z@jm|}Uw z>Uggif>^=k684XU%$8zy_^cpH9f|L+vg&ZHdiCfA%v zyz{{$?6_biH_#C>Ua`o5XD(fok~(rD2rFn3tP~`1N#QRK33q4JRfDq`)?P<2QLyD% zrq!8SK zGbp7#4(radW9djH)I0a%BXcW7X^B&i`y6OgLe!WL5Wv*J&;b6-6d*NoL1B~0>J4J| z6Y}H*dRn4^Q;dP0 ziKeo0ID;A3pRoJ&!$>5RQjbL#x)TS`OR!A3b^!xDE20D&E)B%05wUX@4Dy+3kHh>z zoSWKz>zBId@xxZ-o%-c4){qc)1akO2X!TBtwqJYKNc60u(g(V-xFs#6(gsW@r$kPkg-uwr56dW%8Wf?Y5e_Www4k*8fSw)$6JORZ2RB zdBFRs$NSRrc+;Ek{bRba_nWQ=ODLm#nWnhXa8ooox<%c%NCe*@mi=C;^ne|@Oz^pWekeQuqw76N@u~<2kQO#;qZ_~G-b-vzz zHe~Uv!)w!zxT^D!q@I#UTc7Zo0s_W*vzMz~GdBrFQBCcCM995i^&|ItSArx}#jB*qjLLo#)q&wY2DD=u*b;MrBh?T#T zYdGz@OhmZq+0`T+LFDEGW+aZwT&?s@c)o`4h)kku$ve({&z$ee-o=KlAwW`aJ{?O% z9su`&g2o){kYw>+;4kux?iN4MuvhaDHCcFK@`E6Re6Ga0b6*tYd_qZBhGOwMNBTs? zY5oqA7XR?EfX>Q1U>7XOLgeIptp6jk^Oonp0upZ@>cs>Nl{27iI)#*wW$NW=7k!&D zc*1W1ojam~ab|?&H{RF>#7kMz7?D-NFZupbG_>0wSfOhV!f}3MhWw*P$36HcAgq*< z@SKS3{&$rv%vQl|&I^C>l}h@L5#P^m2Jv!;r15P?*#&ijzLpYd@`#Q!-&+G~>#zoO zigE)0FQm5l(NFiA94HF?=OFs_o9RI0mRd$rs`$e0 z&+`tTds$&Ne`SdlZ;Te%#h-xmJRTSO|2vQQ5~{y_`fF0s`@c*|{wd|b{okIhV)kzT zIahs^^&C*X1eF8y=M8$&GWkuKz1Gcw%{0=BU~_1&IH=0eQKEbEf$JTvt8&j}Og9o* znVN;O_y5*Yl0nSv@oprsJZlYUF zp+Bk7{sfeVJNx7j_ub?N@&>8auwo@Hwrn$b5%OPjeo72HLgeHs-NeGc2{r0_=^H5m z=Ja2zF5rXSZ`G=0acyFhA6$n_HNAM6xm`@#K|4p{r7cP-5A^=#Od?ft=XP_PG@aXT zTDLb9hTpF74~TboS>kJj+IT{Su3m9(2@$b08&v^Y=~|6k@wY4%WFM5=S8qy11)FXF0#CQ zmvu|rP3yi54QzhLddt8Em^66r1{)&^34hC2e&e4O8SCGmFvYP5jRN;|Bex@ynfo>S znNN6-bjS{5a07kCcHrhPjo~yXLq+9@KVWKN?>)f=YcP@;w~=^*01pAsA8e7Y?J&!Z zA_rFTXr5tsRHVXWo%K$UGdKR@=o@=W_2jIr`FjXM&LqE2iG3FR1?`8?PSJqS{ehMZ zKUe}!goKC#0ij?K)B+JwBCnEip5fSy*m%Uo>>?tflc;t3{v?{BiqW*f>BM1Y2UH3K zpd<=slCXgHf7{(nNJqHDzRs$D;YI!*Vc9=xy?=gzVX1!Sv=L*(w9k2ht%J9SqLHi(Kt_$_xGWWVnLx?Hvw5~JVI z+#u-1A!ZNWbw7;5xqZvL&_(j}r@Oiqh>x=e_x2Wy#UZ}OBfoM*c%Hs~N@CiPFX{A+2~!cCL^9wT0g_v@9Xz} zenI+wY`6dW1^??QVr%tf+y7tExvMpyJ#ZJ1KY!DCUp%Zi;*B_F4?5bvNS@;<1}6PV z$PpE)Cu%_jv6>WL<0Nh{bx99?leLTc>Q#$ibVe-;dp}=ob=l0duEcV+!f-$z#*$@7ZGvr0>f8wcr(9`G$&j z;ve~jrj6XxjPuU1+$Aj|1)qYQBZM1;FYFZwoA>1^d0pEAc&dfu(Y=zG|P!+zo5 z*kX#8-|e@n-K6zqQyxIWwb~v#sP@)G>H8D> zU7OL`vUUG2dGq=o`83W+n?$Qm-4@<)jwZZfN&Cf0whR0`MB-O}@G|A3U{=wYPFx8xfGI!aD8Wxx({yY=l< z>S2p@wQsDrRC4!Dz^C0TD*{?p5ZTAfOlr% zrGHKz?I)u5j)eE5<*`L0ax%<8qHa;B6fMquTIO7h>_}P7?~HO-cw}Ie^`xxM9vy|v z`;@TBBudPpk5{l&!Vy&98|Ou3*=XgnlI~B8*h-Vcp&4!RR%lXFQ9~%zk!K5XXX+$y z=RrVl=lhxsZAs^HpLMZ*YW;}d_GVTb-_GfhGz^_r|KdX>&(Pr!u=0i*|d9Ffjq+*WP6)wv1O< zgXR|LNJIP-W^7d3vNc^DVhp1<%uaO@B+*wcD{nCu_g%UP?@0Q&IuPHZH*lNj>guLM zP={!Z@)=ZIbCeMM9oip5Q+uYJdY1v_GqRWJnJ21dDw-4eui~}ByG(yC`a7fpl}A=a z++HsX{ot=a_v;!_0wiHHssc?;G$mqbbfSRwhOQkJZDcbrhVhW9aG0)gC^1#(0%>Fw z(PrY3JvwW}xj7CzgbYX5A^E?s#O*2(|v7as3}V0FF1(U9=NQ)~FLK1@L;FijYN1 zO50k`wbNBwvz?&?w??BQ^3*EX*zz=vHKU0OF@mK69aKn{>c-WYq_T(=ytNt=H`Eu_ zj-f&(YjuUX)V-dZ;~76U^J!KKh1ty+>fotk$xfa&8c|4ua!zlXg6X-aw#TI|p|vbo8&bGiA){3-F}vPYkw#@*q^B2A&!X)O@|6X5@;<~TV6KpeN#vY;QRlDq z#v#pScSjN>hCFVON#iUFwtz#lJv~Elj3X>ya;P`s71A~R`AEBa9v#Z2!r}M&eclLR zzFtn6N*VN=RdO+@Y0kVI;Q{X5daDo2Y}Y+q-DF0|xgGHG?356Afy?+9WgWTrx~0gv zd8@qdMH*oqa0$}Er89Ndv9)M*!--V_qco(lG?;$X)JtBZH&jWoDwqJ5hs`y`3gfK< zUyo;R3!)f}bGh=PE@LZlM&`;l^=ba(!)4+PgLNjIo2MX%wJ`_@j1RLFFSPIwO1gzm z{FH=J8eYs=(?@b-MY;(Bp#W4Ak}1R-r!L0tmvP=MT(+13q_vMi+I6GM04NZv?*IM4Ikx@nbKQMHfj=^e7i!!n6s*wQTSXC4M+K6sJWFDDIVQ zh>I8jG{}xhuirT<_S1nLcx>xYFW!H_O62m~@a8W{RDeqf!avM_QV|G1JN7>^Ft4-~ zh-7Mn4NATi$`5k)rk|O?K*t3>aIRSFjH%U_@@pN^1yZtw_EkSuYxKh-n}wGnlx-qD!PR&S zW^gPa)IiN(q-?Aq@oX6(>=LAy867mH*NdTa`x9y>XVj02enukOqFH+@iQ#(2Sh2C0bcf*KJrd0ZU%V;K%#m3Xi8G@nJ}Fq&RQ1><5=&Xpt+`3)QFaoD zG_9aX(JDJn%F`CtWF1?5u7|Odwr`DPR`x}g?J>DDWhwm7X~ul?r9M4@w4I6BKhd?C z2{GsIq;;!18zSnahJ~H(3HZDoDK=Yv;}NoLs)O9H3u$el%Cte&W?kMKxha^yYHii5 zFPBU!(Q?c!#|E9ZACBB^LVJroB8FWQKuvK{70y ztF{q~{khek2)s7TGlKfPIq-ReC*Re!IMhp2uAec1#zV#Hm7eA$ySec(Z>+ogNuWd4!F<$^6vV-(0V3NBApm)kQ! zZE}MEaY6Bvbj$a19@R|EOX=F)1%-B2cxP+o+o_w9Pz1Nd`t%CT&u9@NB`%}1{{d%g5eE_T9nZz|%UKjDBgw*QayBDp zj+0y^-Z*kzxvJqiDsvCUc$58Ha(qBYMlm+#?yYTZq^N({t*7^(w&-4YdGUGIyZ!gu zH4;6IrJw`S1Lu!W3N(Z-jk%g-e_ou zv~HC+8WxsbAU&yRHf0c1Dur1#3~>ZgNDz8(jAO{aJWNGGVgg2u*U(OQJh`dtI49kH zbf8>%;!Sk41)1ug-30Sqtd$Oa3!61L>4L=mV|pq-8(U_Rf{mj_g)3TFvosXvBh^5n zA~s*S0#IAI6-65$m67V9RS}n^H=G=N2!>mzHjc$aJF<{u1$`FfHEKQ6W4zFGZJKg^As^==EW@h$yjP-^)o*A!Bb9HI z7NUV3k!!?Zj+8yf0A)JnEjM@<4T8c*#$=w@Q$GRY@lJ9>H9I5_Eaf_*jfwu+vcbvN zN7Oy~rH_?9R_VLul;s*cpI8a=`jrFPUNMtI+;8C02wz2@s?D8ro;9!88r3}0y!dBm z>`JVW9CJ#Ul@0Vf7ZX#}kOY8<55M%so%;H|e0BewD))3xbRM)4ISOgVhL?LX7qd3( z#D-+?xvF-Q8G-Xdh0{0>P1;R%^zoPjAXjoIMqY(fPfZhcJ-8eOzEjOss4%kHQfZc+ zpfz7?7?xUpPz#-5H#?G@$X-}-*b|*$A04~4!UMjx(gXC^w5xoN?n`3Y68TjQMm`N@ znFp(O#VwopC47;ymLegCk>~zQx-GTxbGhyoz+9ReT=LSS0F+ANqj*)o z9j(cTej@KBYeBOcbmOaa-r$ELZ-8$Jw2(?*Y2(MFwksl^Y|9_nXV-EnobN(F$UMEy za7;qb?2oxi$c&ZLOo>WqLbakZj#*QpKk4DySi-!-1zugiJi&z^5{B2+Xa>)M+YN&E zJ+~j2G5%%+l1C>GFGIf23LSno=E}VRVM(nN17hz=&oZ*xG`DNy!Atx z?B;I_dP0~7+d&eG=jkHn;p%~mz)j=`Ut@^&gZ`|eS$$N>7pY>0b{>;iF*VytWHv5f{ zhEG%jCZe_5?;8GleM`@G3DpJbu`7iZP|v2a=AbMLE#X|%4Pd3XOw%u zOzrgtGo(Hc=1f5oqR zDN!kDN9W!cV9#cKZu~1};}>nAcXvFYd(h)@4Z}plDh0j2LtJQA`WcqU5FIU|=XZs| z{unb)Bif9)mA*)?WXJPCZj|^3owWT{u$~I${?=`B$=3{KBVQ@bh{%d`p~J~&mHKS) z9p;Xgo!$s1qWjLoC7ZTVZyU2k2hCFvg$X)U1Br(nwFQ9TqFPmMU#8Z=7L?w|TAx-` zmfIQK40BM&QC6AN6lv3^^DS+H5ffwct0hykP?M6hN4eeD!)v#e_t8y_sm4?u#%Nf|2;_ zSe1f~8&qji=`JCM{fjA35kJ5ACp)@{6%2wtGG27`csg+V{`K$$t&6k6#kR#zq%n*l z@-Op2$7kV$UuH2O*y7u=y!#V2mlhCy@C%YT+QXutLt9F~nujmcb{URTWL2$)H)_Ne zTQ{PIyaN7bcx}kJlu7VZ(kx{RvV%V6;X8|=h!Z^;F;ZQMX!d7 zd7hf|({&$_BSG_L8We?!vBBtD`uO@3^TJQ#cf~{@F@^;e*0d+%ItDpBk6Tr;!g9K< z4mK1OC1DKL(C)v{QLoa{?HHf&zn>)L3VWF0OT+Lr@3+Sq1owqvjdL4F*67xpCo$`e z?>hu%<@<<{HR^>+Uoj()c+kg?^$V0k*{Y_C5X_Y^yfe=Zph2kxSgYDYLzp*7ad55F zKfwMqzSL3xIaU4s?OXO&TloK6LUH_meE|PcP4$mIE=L2}2Tu+AZ?9?6YEBMD=G>s1 zm6vc*(`n+Cob=TU{U#}ylnShM&ZT^k6$g)z+Z-r*H6$f5F|lUXO&O(iM4MEEVzngt z%@TEi$8Lm&arduR|HjTSedwmK&#f-cEAQ>6zf(_>g$%scNWaX4mFh7deK~{AR1s>G zZnV4Pd-QAf9z22~**IyXw#xS8JQ@RA%M=}hA_+DqHMS~t?DRJd!XjGVB)uE)wulTI zZuW8#_teoJJkof7X5nqoac$M?@bPa1@Teiwj6P9w?hWX9{2t%^;P?4PsLJIdDF)A9 zWz4`|uw##&wo^#W9~xKr3>I5~^@jp|g9LnIXNc|gg^Gcnj_NXn(Lw1N8$IT^YT?)! zCRQrrsa!L2kEd+sj#^#XPJPdB>;hJwlq`)1d;lgEHo2C4zob#zP{xka_yHXC4dEg} z3o;Oyrf1|F+P-Pekz_Aj-KVf~MmKqsy+C|}=|Qugy+-Fx<7^}j2xjnP+bsJ`>v~=1 z{U%e5YH)Qp!P%0XN>3>!pL}fwl4jz7XD>gJGpYYbi!sx{6nNs7POObF5mIp{F|8=< zmjE+_j^R=imAFdA&Bqcyaf@}7iJS~nsBQ;S0{(C_sCd6s4bQSkgda^VBc-+?u<2Ug zx0fLL^d{GEqAz@w!K&>z0vJpGvwos$q`}KrypBT1Ps7P_yE_dadAM#eXF7XtS=IW<0ky2OD6aU(5zFtI^HtnDeg;!8!NgOuH3!XRti|<%EZ12=n<_W z$r4@T@ih-Z=Obk#JEH?<#$2ZSS)0QSTIw5GSlX168R8g~dm^`66^@3bU^wKd!)NC> z4->l9NT+Xx;a>OW_6`;x$t`|)~tO>Q}3jsKZVV-tzt%y;pMzYULx*%9~$#3 z$qg-<^0^=o5}lVcFLo_3fiVSm!C^~rSW7Phk@Lr_Ii#j4i&HQKv}J4CVFkcKgO8X? zkfvqU*Eb2hjQH8@(=r&%e^mA-y5N0&eG*0<$+MKrP$HT})@oI-KCwZvf2j`P4Bba+ zAk9&EK;ybDu-4iGtd!LUo&w!RZ=mowG<4)z4t~4872QW-!2O0V)HPs{j78a(P+;a- zBpV|=7oRwhnW$2we|8_?Ld&&|sCzjNk0xLBl51;;OF+xi(_9vUz?X1LyRE?UR(km-8x zg!B1Jz}f@HU->#ZRA8S0=aZVOW?-B39Ul=jnTFP$Q%D`R-BG$vfR#7OpPI99*WkG| z^zV*T0PqG>c)LqEGs8QZW581!VfBJLDqt=#hfNeutixVouAGu|-s^6>Ri#j)5feN$<2 z;Rc*kY_T7uh;12+mF!oNM6kU8lg(&~7M!r#0t)ARy-DMpA|J(?r!0CStH0kqIvb!o z>v8KPdkdAtN($}7%XH)}qBb)1N5)M%8C+*3_uD<~8MYGS2pY{Rs3zoEl!z9=GuDW& z!cGV*$a;r%El}DJxmlhu%SSAOZeq7VwfErt(ZQxIn5o5`=%Z#YvEGsTk$$}PyaMw z5twb^l<$>gpU)Tc?+=%dpc$$mHlxY*?PFI!`!Q6=%TXG+)xYk-Lv%&$-lM~F5u#{|NROt{kJ;Djl zPd;T{JUSCdqstD%ZUUPzss*KysBK8o?~`bEDn}Uv5l$9FDOKQtl`E87Ob#2Wr2o6< z50MAgQ*(^qCKs50l7$e8wu)BXIkKe_ceIpT?yu6l!2Py5Fn6Pp?B(q^s?xk$CC6mm zXE!_*nff4aOn4J*l$3IJ<}zz)OgR_|2Af-muDHB>{vCYbJSnb7F1a2dS%tklBLJ4r zza)koTyZ-TS2>^(^HW@2ZW|_R z`S)gHqd#e)BI2n2e+=p^vHD2q*O>x`bH20fV2WsNaEFsok>H8BuK!4lA+nS-<_f9i ztiQ&B_hqpk$tgQZ8?o|(RUM$H5M@j4-|skL2kdiV^6N&z03^t)rBp^zyl4;p8nYUL zW6VyZ%@W0&458o+GV8`2asqO2>myMzsZ8jKtA>$vV>_`4r8+K|xSv_^UpY75!SvqI za^B%Ky&-f$1T|&FE6e)TMCZv%3iSX3U+LZm9HN&)Xt$XG>P^V&R>0XaOIkp zh-)ofF`#mR4^GZWfq2x5YeP;W^Bzy2{kh>N{xH4=*EIE@7meGVwMT?4P0g+rArqaH zGk?&k2e>}8fTNWMx?6s588y|#BD3yLqHLQ}i3tZ-eQMDOk`$yXjFbzSRI;S94?OXf zNCjkmZZXpYdX>_Qh+;R4?B}1W2yC%bnGK68EoO!dS~`b6tcjb56o9k;}OQzwl$FYQy5d?}-=g6LSIo z!7InI1Lks}zkRzv|L;mbmjAC3@IQdPf7b1bKCnKjLl1wsSfnn^os(#H+j|5Bp`eMV z198v}k$)h8kbf6d)J-JQl5B8v9}uZnR9|@Yqp`lBBj#rW1}auI^K0AqF7@c>G+(Vf zTG&<6jsNvNy0mvol9L4S;rG8YI-bhT;Br37W;xEz;7QZyUHPyh&MYEypAYlt9^z<| zx{1NqRuvpKO)>Pg`TkAdMEpWs=q`R}eS`HE zA;zd1hsG@lh5&GHr0DOy{Z^ksTYJv$!z&2E*0%76qjkuE*%)}h8LapD%=Qc z;5vrDamns`7wNX+yrrLzw!cOqCYh(ysE3wU4>44)#m&>^JN4f`a;VR2R@Wjz&m9L_ z@dt8JTZ!@xoiAX1Ba;Gq?sT8^S@K8AMc1ffAF4>7vWdTS-lJ?k$^MSV94xQC6Z{>H zIcOCgf1BF@?0!`0UI&x)vaP z^0)s?|9g6*@N6)5x2=3bD8-+$HVqT*S&JrsSbR3iP6G_oLwc)Irz*lLjZUJj)NPS7f2bNkD^4EFhD!<#<=797X_cT&>u?s6?E_~c%5lD5|! z5GUFsZD@~GCvA9**~M?XB(77o*GgW3jOl$nr7wxc^k~1p-V=+; z#%eNJU54Io*Q{7d7v)X33uHRmB{8aWFKVOmT$iWu9F?3gf^lLyMI&lGSBSQTHENKA}+qFvwv4s z#ICwyqk9YiQI7r2LL3vosA2_k)XZG86BisPC-&~<7Jp(9=VJkH6b z?CeKV7Q&c{(Rk$(q^#p&sP^AiC>1>;9O^T8t31YbyXL=L?Eak0X1Z5A!8$>7MgpPD zvW<~mMl06a+6GohwZ-{Ow@zvEq|^u1yklOGyPyX^TT$lAaI zEMb0;n~pCpzrZu^;OPF2t;`t%hTx@#F1lwl4>*=k@y%kc&Hxog8iLzGT}qf@AKUy! z`CG~NDs@=4m#x*qiVaun8x|&atOMzcNJ_S7%v}x8zi8rMjvtGyK>G(f%`%;Q*^ORB zYGb`5NjyAYV}H>x;=vlW8pFXF{28sQOe9+dI?}{4j}5Wio2gtj0(7it6?4!bR|zQ+ zZHm`yQ%X;r|1Gq!@@$+GWS}KG=WLa+(5P!>1g6?N042@QcL&%V&|3t zUK zJ*5IGdK}Ot+diFKe9AOCU$2Dz2dGzeM2i@RTye_xLWvr+h*@VcogM->M94w^<7aJ9 zd@olg1Arn0L}PE7IFnWm=`YEfQ7n?9lv0<>5vp$UMODkU>ePVo9U=047C35*h;<616P|532o7O;=ZbM5uvc(kgbVxY>*d}FSrlW%@D}fw<5v4sS#OHD zD921WXY*>MWM!rINktfc6bsuTNhRe#K%IYQ=HrtXXNwR`fdJ@*)< zv>zJUA3_UocJ`v4?eRkvk8@0M89dGLQKBYNnJt6iXd4oU%#_UZWhffFQ)1w3gjMaF zt|-aDjy$Q}d65=}eW+?%U>k&*Q#t%h-R0x+9_1{G+a3P2b=W4(eTPa<3eL5%>fNx? z)>e74K>2)G1A_JqD$*eIE6yh}x-DRpi4IpkRH6(l;s@`VL!7N;D(R;GSyw_#2QbZ? z+guYaaH*3TotH5wj>J6=e8W!4#aec!9BgB>B8{LMz*^HFw7-Ajc?>@$hzzjdhCnH< zj*}u{I#~@fo@uKxI}X|O(8*b;drgMF=~FDPNs_~sdA3D@1S&6`b_H=XS<=1B_g@Qp zd#$KW%UgT?&;dgG;)1ZUzhr7Gy@|IzFURnwmec83CfX8+e5%O>%2nMYH(9i@?NroK z{p?Y)Y+TeL{4H}_awzwiPJi;V3_)KG?krG^Es=0(GcOz!h*u>m)?NAyd4tMTu72KB zkFvDy5{E>=qLjDoj_VQ(d%Hwn_IEwFq+gj@(>|A_T-D6ekulC*1F9I);z zCa7O51TyLH)wF0?hgIh)UbJ{6*48ho0If<2z4#4U)Ku+S7v-BL)ThfFhRjhN7|_CG zW>LJGF(SHc7m``uNP4^s!0!Hne#|OQuL0MEN1a=|^nFLv8OpBKfMO4c#riFaG(hi` z*B-A$bpgfoI?xjhFhggSR!tzA&WB>ReI>_&3Dipx(~C&HA*HVNJ{r$!Ime<-ic0FpmA|}k-_#s=7FYUjz2d}3%K0kg?J9?1hvBvc-tzx^OpD~ zn21RBlJnYK{h9ZtLSPj*ZOyZi?t^7m*<04T1|<2hhx$UArEtW|nZXLFo%)(p{aN#A zRQXrMK?`W2^P%EvTc#MZZne|%|xiOGJ3gb~%3 zb$&%Z^mqTn1w9|ieqfSUvR6(71(aQ3NQ;RrpSUD`C9EBvJf@CUSG5c)PO`Alef=wE z6^L(FF~!=wgD;4SmO{gWsc%7Xz=f$EdG<3J&ynA6%@wam#s^JbX@%F+tzey3RUL)J zQXxj(`K3~l-4|W6Gb^B#j6&-JoNr{cg)nG)?3tY&eNpZjqH@k=FqW#$Gz#fU&SO(c zE)%vDqLtfC|;?`be`2fXf9rs!*Eig)`AbrpYM@z4QqjM9s-PsDp++Mw<;KG-y zE&Pz?svq0jJxS$73JeJuq2#UZUG0vU;Ww|3f%WbsRh{m7 z-Asn%S9u*23>RlrTay%I(pLlHXD-(*{*4QZ%FJ>+JB`=!NgIDBtXn@zw))ZJ`7grt zA~_fO+Oqg(+=(y{M><{)7sX%c9nX&rd<{ppzlj_nLbJ^SeXEg`_9Of4PcN7oYl28a zR-ME%ew0^KOGOV}v$_)>K|}!q`NnG;89< zob@77PhK$V>Bv!~YU+S&b)B99miom*3tH;hax!I`c~s0f@%%>*(gI1_@b(@aCxx9d_Z^iZ=qSDeg~Kld79LYCb)lMu6J33j zNJsm8^9s|}=0+=U)uU9x^E%r7DeVt$4nqJF-{Lm-#wKN$;rG&ZUpL*~JVLHSjK?V3 z;r6OzR>co9q&?}OZuWEewNjb9l?4sF-92vh3u*?PtBm*brc&)wEh}6-?g+4e8eiF6 zKYFtaH^Ya~k5;EGDH+FnhPjiUYh0m^gE68buAJpA^j7!@M}iAjgd;l#>Z;iK)n#Sc zZBVvc6%D12OaS@i-Oc9gE5tBgc&7-vRK$aYWrzt>_uuKUmu|tDy_(bN4gfn#liH#HAB;Uq?M0W71{SX%Z0b9Z6iI-xJ7 zoodX;3`}oauE`uXr#(!OBZAW-Hjt@gU2x)J7v&=er%TEQhKJhED4irlk~e&4|HQ-Y zr4i;Y_su|rgU`}FQa^k?z#e#%)(K}DxV71tahh`yy+$_i5NTONIFq;b=xm$d*_@+Q z1XC~`ET8L;JRJdj637B1P3F!blf1AKOFC-^pwc*6#o4hm;O*ls@To0r)JachH-c-( z*AbTnrw!^`AyLRgNh#TC2$Vy8Vz(Z8-6r{j)oTVJe>ZQHi(cDX1Jk z&zBF{j&)8ih%OFk&rs{kdC1v&y5*c&5Y+%ppKI=ITI9rnMpbmoFnNZnytiEPPH2A~ zI;oz&>qw(=hPJj#FlSO7#RFAs>Acn|y!7d)^?g+n*aKyob_hN;n=?`y!A@6`Sf`AQ z(hmM;r8)010ixW8jvfH)+0GT>WGmAjXUx!8+01fT1-1w}lWVX+UWrSEkCex*?=$U8 zw9}uw=oRqElbZ84iVcIupQhythHxn!JQQ+dA#h;ew8J>c=!4Ck9EO%MLm@nEK zd<)(_ek!~3)|nLF(nN+!K|$K`?VZmy%!fDW`ZS6xE*C}-qY+gNYht-zdtm>&clr5M z&+X}j3eIBBgG08y*8uBiuU4Wr|HW1tm&Y7JU5fce?h*3jaO!aqz|X%BkRZHqKX&SV)9b!vQ;>&K$M@Ixqbvs0H}W%B!8D8&k435jta z1_8e)7vBsumtw%1S-7{p&v)FwABaS&7yOJDBNunWF-yNK9poa$_Oi>~I3q7QdIRdi zcCKH0f3pzJ5l5@8eB~u0OYz>Z{=9X%`b!8O_Mtw2)#(l@zFm32-Ti&|ZgR<`fEn)J zS+wy;sxf(ObS9F&jf*&D*dCJRPD8LVGctoSlHR+wigF%d*PF`R{G0PF^~hM(v3*7V zopXINo)$)D6=v;KmVRc;+=nF8z}21b;NClVE7pk!@wf zs{|jTuR$*@A)g_^wSOtQ*_{8Fdu{H4txXl2m>7?QXQf-D`>xDv^y5*RsL(I1M{|LE zch6j5W5<=b#ROKurE2RRV?GX&V+*jqNl|G(0wnt+eL#L{Kuf_!KZA(h%rxROp@2N{ znCP)v3Z_j_n+t_SXxyK)DKs+L%1uSbK3PrqEbCu3Eas$y5x=eQw0Da8jes z$(LiDSQhurZ^fuyP~L@NsXG%c^7{vW!+jzsD)nPSCWLowZB7uD=IERC_E?wel`D0} zJVY0z8n&eH&n*SfV5XX5VEVEb0UG`h^%j4BHzT1 zirpxb2u}(&WsVlsvKvz*Qq9|z7L@TiV*n3kc}MukQh2R3XgN^U7{y9ZqO6s#aLJA}elqxzgpufjlg7 z#p-}u9V?jH;!HOVoo$h3q`7oRUDWrl>@UbDIjB>`3-(AOEbc#s@5ElqA@?suoao%6 zi)X)~H-l~AnD!+8^qYWSy0S7cJF;apn=HmNNM#<9H(}A(7~cC28Dbb?^oOyKn2+t$ zEDL^FnRvJ=$g$v?gmkv%j*dVtDTu>0Vw6XhR#kLR&=K6wrOJ_~B05^6%1kyr&xe(g z4sTbl3mF}n$ieZ z85b*lF?&z7XR+apV`H0uDkIIA@-|YVm)Nj1!~Rh#CAr#P3wN|{O!c+_fs^a{CNo{oh*rDLY-`kq3$q_qy8e8OUEF5t0~ z%rSk94wy4Jr6+EnnQ9?!{rm`k{YLMxxc#=sx^qCqr&e%&ayU#R=t{xp*u^fnfXewR@jjyYJ3i zV#0+-7xHIbVOn%vIj>U4z~z*ks7BpdK;|sEj(s5qbNJ+r5*6Ll%PD+#r!>Z?&ttfV zV$Psn;r!9lw{Y(X3}h)udy)UeE<t&YF*tqnic?n%0WBbH|P zgB>8%+wa6`A~)Qq=gJ))Ts8;6yJB=N91LV%?j*W0xEB1oGl}+LFNEV4ML!5PXB`(! zK@;R3OahaEMKl&mv&0K2A8-OA`AbWaqI~8%E|mNW)(t+QUNjaz(K?L_h9Is(*QX+q z5K?Uga}xTyy6`m)T?Ns$alzJ=&yx@~bN*p(#1US(L$*P(!cCMQO8(QBdX(%JgLJ)JiZg=3lo3# z4H-;F6~2>@Q00=tT(|T9a5ns%{%%-jjSJ;bAe~){@}t_CEC2yW6s4k(OrygZzo z7MBvAxFo_XKYeeg$92b>iI0CLin}|H9|MZdp&*362@zyBX+8G<;O{6N>yC$hYte9` z7bQB)sOss>e=i-4buGq-T)ZTV>ZhNAQud8?#XD?~=f+7;hJqPQ>6~`P(dwS;AVoo3 zf6#BS_+qjNS+Kq7Kj+lS3ytQ_$LOLo#S}MP{^ z{88~BH4un`c~yuc8-H5-&W=z06Xs{mWbgxbQ-Dhwf4KwYi_zNg)j(ZkXfy1& z5U0bYIDY%06SGs`3HW5v88nJYFIVw;4CrN0|Mv=^?#m3&)i1h<(xa0`20O#Nb!jab zVoVN>fc=DZG@G&w2N72Udts}g1$*h&>4g|IW90ESPL&1ONMb|bYU2LGUJ29l2sOlP zp0r&thF2_;4A1?W-EjRc)~h?kpp&zP=Ds4^i?vAV-Qu6;?QX<9iYR1td%>WupOL3~ zK^?n5l7O(J-3XGu5a7|=%)yMEm_^x>4S)MphRey%ME-8$)PQcztoaGC%;@xqV*nY8 zI(Y-^jZ%9FBRSgrdL}jDHU9C{u!qww#cs*j(7sH{XM%Z<(|C`65E!JO8RW~N(sz7~ zuPp8iM6P&V5OnPC`D5rAb$({VW6%Ujczl(ovJ?KIC^Uck!R7%OpMG&`{CGHE#EfxW zRIi!VEg~!aIvwf9#Ol*TE0fVgYiKclU=!6 zwyKM4Y_m7J{qL?Bb^-)n3ZLX4GRghs!rh;!K&ckfTVQ@slU@`){LQxb-tSWx8sjJz zrkB&<&aRR6A-%=hZy#k{Wf)E54u@bK&?qo;P z{9#%@n2$er;)1F$jpY@yh20oYY7U>?5-mh1Zk%_#?+g$8fGpDpo*t!3{IJBn2} zBZ!>N@Q1Yxq6*F!#Qp<>B3M3?5`0SfVGw*dwRuCKoD>TWS*1#laYa+#Yca%#hT-o^kn2riKQ{XD5YKrIj0#She*o|jGUgHZA$i0zKNy&g*&D(%9y;~n%+rFk^JX~4%}weM zI@7U@rFS7Nv4(hcLBF^S1}#mD9iewi{jj)S0i0A*iLRmXEFuhHOxr)EWSr z36$Jf<&QAOPwrj6nao0GJj6|5|2;H%q->~l%Mog8#`U!h7vJhFh{Do0|JrFlQ8q+Q z_t-XekX^=M?ixw1wFE}N!ccqnlf5x>m=N8enf{1`FXYrEZ1t{adNqH*8Y^;Dbmr&Y zYr_PZM+_w2nX+hec5ECFBADv6U3_~ck395ZK@Y8gpji5`Y=8&37Qj0WBaXCs`6h;^5EZ*eb}Dx#u3G3DlWPgJFw)xvFd!m}Zn=)XK6*p@;R z2=t)QQQ2lqAUhJLH)=W)=1c=1x79&VNs=n!tjlDWO*jAnsRi{dnDhW(6NlWORff8}tMl~bBw z6^{F1)&s!Q}ZW8}O|6L@GmuZMi3mH97Be_6=0wNxDbc)-g zQ3?soeQ;hlY(jzz*R=s=AF^fid-W9C$}xj;@AZ~B<0sn0k3$4b(uA|MraL=|T{pBm z&;30|<-daWp?~|EbG^pKyn5xg1(BcN=f34NN9OktDcbcIT8V%54A)OW8IS~+=JQ}4 za77%x@utP|6V6GVckBU*zD#*<>I22zw0RF^W$*MvQs!Q<^HR=BOdEYq=({ta6(uez zXZV#BXE!G)X@u-2i`h#2C?=Ivi9oa`da0gSO|v4If|A}DsTcX_sX`)exT;_MlqZIT z-CL=9_aNkY@P;ukgF6tBFW753IR62wJ`v2mHe|$g9p`|?Kvih_tS z)4bUC(+y~wDc&)#-+KsQG`drI4NuvAXr>zMpxVBMHrYXj{t94RxQj4%fDA(j6ae=t zW*7r=E&6Q%@rt!w1$Ir-lMB`h`9jyfP4h_u?$^#R2liO>`v~fe+WZX$L|mHhQB(Kb z!+ltgBjVSxU!CU4mF5&rfyRT)O26&0_jb{$i<15E<1*E5LEZ7=ihH;6&a9!j=cD)~ zc(0bgY(`c28(V8OvnKO{`lWiWPS3zvMgBd~r9iK;|2S7=-+k>Rdat}cP@tCO7H?8@ zMQiEIIg()|NDrrOq?D6v4ftu-)`i^Z-krC734Y9Z_m*1hLEfI!C(`Bv*@^HfGO12X z_M+bV?Nw0p#^ei6M1bL;Lw|mgn~Ag2cvN1d_Da2VBGXmXlw));DSrtWgfz<)m{-!b z{dZvl5*CSoB9J!1&hSju1S=4YznZ`?V(Y^4UbHQr8hImtG{UZdzb_}>Z4tO5FKwrq zLOO`cjGtkcW~|9#V25rpWjJME5`fxbDW*R81?#vI9&9<;Ebt+8$>;)E0@{Xvk`tr-MY_ z@cqIoi6=E5)DH(eMtph5oBWKOYK0IHUjro3{O*Dpdc+$p?-9n#}mm233z9 zoFB#t?%&=Q&P+2l((kh;FsOs5WF(kqVx(~2$Afu(bQ`5G7@JEE-T+0bpW4*BbunvS zf}iMM^h2~pns+g)SO2uB>+06)-2VQvJFQ@mvSWsh{uZ9eb^E&OyLbO@;nNwxx1*jH z$bP#u973)GTfE-95XTY|_}IR`}ul^C@lSBEb*igmmu4<}4y&AWAI zl-yBf+Lm8>r6gv8k%ihmosAvK{YVlH8~K6PjZ+dez&kyn=qAP*)*NwZ0&@BVA_M-y zK_icZG@%fRKU}ubk3}`*;ZQ(7a;L$7JvRyAPSjOcW~HIBCXh-eP8QkZ8P?6V={H#6owkshctu=oD;+|8K$6* zMqUG^_@#Tg#w=A^w{8_Lx9*Uq%a@`oV%v^_bX5a|+7mUx@>S=_vC1Q!);!e!1^az9 zfpR?VmGR2B9QboG8j+9n;SBkla!^|)Y>W8VHGf9!Gzi`6mD=T*nZr35nJbH2D3iJG zFe!hKpGO_LoHcxD_+tAUvCN%HlSek9fIIs!U?wbJ$otIdP>;|f%KpQN$Z*zD1pE9@ z#5swHsca)gcG&UlfiFOf{AcPf{ZRnZ*|LYcUf~hpp^W~Af!;`#Pb)G?v~9V5vNM9=S3!*Kh`rve2jMMhCx1U5=ruRzMN+X(dCl1mw!gjO9FlF@{rkV^sdw^-gmP; z>df646oPrLDc@Z%w00;?*o)5WoDjG)JjLIs3Am@*Gh7<}#VgaMPrJK6mEGkf+g%&w z3AnGL+7)$TtfQe9$5GK+Y9KAID=eJ7ovB3NTs~tclO+mKZnRsuOdgzshDM;nCW*aL za-`LttV(!U4Xb$Wzog3VYuo-&iCC=qH52Nd89$HUl+nv4%Jh}5=76#Sl{c%&4MVX+J@Ye{V@vyUxZ7_2f zyL{wT@jTX&Va<;$(+uP1_*EG$PTxAHsd)>>@$WnX&2$?MEuQD6vit6Q5wIUdF%rYB zkXo&|u0rq}DQvQ*#B#WNyC%MbfJgj^)RAz)#YOH02V8u_PT~=sqvmB57U6RjiGuW! zugqO*WE!@)Q(uV32#K!w2&85?Nfmu*+oNmeEgqLl_f}+4POM0n)g4)8^C(&GP_cuT z8DxPRq~<6#UC8_mieI- z8@}O@%2R#DLM(X>%5w+m(8MsY>*5xKe#T;xEvhB89@o&s?yyi=NUJ1D(A*#}=0ZL| z;3|l@+fQW}r`b8$B;g=qGaFW!9T4nMxFx)UvR&n4>ZSnJJ_^KOAXq$c!UDWMdF zs}oK_Q9ppZqCC5`m=8GVCvRorj(l3-@}9axkRQ82WWwSEy!H@TY#w?9c>d&1mpXgGd0uDzR7L;0I82@O+D`RV9Hj_n zXs1j1G;iB8N&T)slETM}b(+baa5y4W+H?4v24PAtw z#g2g`btXfS?4v0UB&wG;;|PnAOKaqd;JL~oKeeTMx;5d|nLjEBIKX+I(PxUY@7-B* z;oP44P65sMP28Cr6*Jru6w?k)uD3+}+l&66`BIgK$1^W;U0zWC5L{pc*~RRrD8 z=CCj8RR?`f3D!bvTRRpvD)8rbhmtG-j~xp8(fA&;Tpn^~dR|$iHhb|>E*{BE=^9J{ za(O>lzlx{#p4`X6A1mj{C`mTL!V3KD^1J>zEy)HIZ~O!X@ND!rnXD{Tw4>V&`9C68>CT3@e4bzkT$HW77KMP=(R zrDET4Fm@!xjCu73Gh^$b7g**D8W$L%Cvy;1!ELu(Y1^)joG?gT?O}IG<*s3hIikV@ zSUnu6J*SHz`)@at^nYc3cZ9VWL~Q!fx~18?&VS&`{CATcmWY|3t}2wNH`$HX_cSYI z;XGQdtoM&2UQxiz4C70{>=(V+b038{I__ z2V$s@#X6~2oWi(Pn6MmIqTFYN$TV@yUxKKOjCh~fOJu36*)|fhp=R1aK`OY`#-sQ3&KRxTB!5z_6X z5mTs85Lb3c{0Zz5lgdB>#xWe18UoAl`v)*lg+y4Ll&D9+(M0qU3Q>y*3Q>i0RYV?j zi^L<=4Xbf$wyne^^LSE}WOhWJ6e|@=SUi_>3VDSD6&+C`IrlsM?S%P2V^L8W9C$B0 z+3rGjq}G90GoGJ)AJ99<7tH_Oj?b|j*UOZ|eSByC6wM@j%tV4TWxz!A2JvqvBA5ZG zu<_Uov2dCawaBsW8L+1)VJyDSnJ4L0O_&22(kX!qCld)bAJ@gCQ(90{NZw%#TxQS- zMaf$;*Y^S8q}3pv&!Qe6spfbZkYA;a?O553l#|GQKbU(VacmqQN<`l*-PmTPJDz=A z{GH95kg@L-sevki{n(~+G?B=`kkJ-Vdy4FFvK3f!bc1|x&=w#3c+c{XB(SLhIOgq? zNf8t!VqU{vWah$Y%F|vaK_MxS9Y2&Fqr8}vaKPG^RYGgdI;IkJNY@2)rj>e!P$>eA znNOsF{F#_7fxeNy{9x`i%P~$q!k}A814p{^7p~nI6yGs=b8N+#n>3y8Xj>kN)MrU{~+5B^fXHy7Tw@iRz@dp!8gF(*Ux^H}<29uMnncdro zTRiU2<#or4d#)GiIi4J6`a^1U=5(;C@Se_>yqut4nKwwlZslDuCu&E|V`T3b(!c%e z;}@qU^Zg=vX5+eE)vWH+F~zwF3hT(3Cw}XFSZZhr}u*Lf)x`Hpa~Rq1R~bs z;s;jIugq$J*-!ojZJ`AOc2PlEOREQ3Q9;Ih*5l@meBZAa(tJ~!KW`7+AJwFWiOe<+ zls9<|x8_*G^f0@$h9}_NWfN;iZ$Q7LL`P-F8nd$A8A$I4ST@om4&;~jI?}x(g z*oRx-N5sc`BJo55(wkyg>Nmis0T#}K;gy8of$(Rxw7i0swaNJ3J1@bLDa!{}(E!rE z<>SCi%)kF^kH8O!fbxl3ZO1?}NAVhKjysD{0M8P6wnJ>0slEZd-i$zv}Q9nbi862v%kVKOsM`mk7t-{Xz3 z;Dqs#B!~%tckly*FLyA56$%M<^Sp&Ky4c}bg>U{!7Gt05!vyv_jkES^G!j~l zrQfUGk58xvf8X?6h*g}2zT|w9_4)M)$ynUAjU^6RT9Q`|W7W4qC$G6FM%sr zn53zqet!#4WI3liAlRy{o5}Rps230jOY;Y`4%aZODn||CqNhvAqUHdFJKo* zXLl>oNGb^!J&m4$0jRH_slmv7q)9y{dP<{?iB3!3z)MWsSp4MDJiM9=7TXkU-~X7` zF*5m^DW8L_lKw*tkD8wN+&A2~;gES5#ezKULOi7S0rp)XJPi6aC0|%s^`dHdcHJh{ z+;pd&zuHAKcg@Ok14htj~lGYopavde%( z#+`O{CMX+kZ!5FUVmpmbniuxTWBfwABsK=83teWHUcvclZ0z)-HxoBOIX7!^#7&JjMGlA)~s7Rn8Uqvx;Yg zY)%>_si)f3F&571rAdnfQ5q5^x>_2BdOdw@gBCAmV{c<{dF{+H^R+VINxRS>fLmtY zJ^}=+(^Aq?`@yDVztFm0ydyI{941fHSFZsbeoVNzD7Hg)FHy@8DN!T|A?@@TvO6zQ zPrZ*sqdebIHKVMeD32HpsI5T%RaJ?L^;IP)iQ@ZcXVm3i!zs1EJNPl1YcSSZGrFq4 z=RK3xPGz-qg-}cXV&{MWj^*adzs>6-6&n!GsPdQ-JZU7$_nSJ2S`#yJ&MfTAl;^w` z)xs0S-GdNwn6H2vuz7lJpsdjyBEP9#`+Kv(c58!-eTlP?HnrAVi{53^bqgDXHVi6# z;QKx{YH5KFD?fLaF#e(H_hADv7bsh^*dBOj(oX|85t1&a=2mLXiQ{Bg7G;NPgtFnMs)JDKJi zGB&aKlX__*UAEjF75SIN+;QmUKUh4Gu;$E!Nl`;_zq8!y0+DaMnAqJTPYo*J z)7C)?jzq0fGk>9@#$n!RY)=FKM>(oFS|jy$@V0~a#S?@{`WP&X_CkrW;`v!QLp>bK zXq2X;AOyQ_in&(pT;jx+YW}{3Kl4N5aAmMX<%8eHLpBY`1q;su@3Gnah@^OGG3!kR4s3a&?C^mXPh4&?-bqcrG>+i;8(f*oud3)Q{XX58cz z%6c+9vYy*t_~g-UPp;>q3;q$4-PU-2w;;n30@^U;rWc-U3Kmx+;X(%qGo&m_^)D(TJl&?I!#m@0KUOk1zY z!p!hp&|M&q#KOSBmauKzTD&Y;9I38djQ7$1{y8A-*W>VVJrTX@i@N>AmuwJczlH8; zdiY}CMpbNw>SfVZwnmR70~R%U)$j1F%=!Ne<(!t zI(Is!{mDnnQO9B!C*_IlJFx2e zp|wIrx6*f%ez`9$KGHo-$E2&Yznr&#eC@1p@tQ|DYTW{&!?<;owG|kpjCr**Cc|8w zJEBx5`-BCF3m~YO_*qK_81~d1&lE-{md|b>ouz#Hgj-mCM0?^ED46ME!I~)WDzb;2 zrn5gELF(2jwq7HZcUR9xEeErBA~Wn6a}=n(J?iA)o%(e@amV!SQ8}#GgqU#>vBKZP zLC3@&y)xjT_N6W2XP%q1V^;XvlAZm=H|AmeLb2&yY~Nc*t%QG!uQ~(Orh{Em2{8o`#Oj850PNfW=C!-cEBNTtO}NN*B#0X=kf27hPVfGH;>Qq zGYHX-?#hp@0JdE&jjGbAACc({X*@k4=#*xQfu%& zc#)ws9^%XKx;Cn13R_6Dp2{i}liQU2GB$1$$Ysk~&3MQIg;nH85rw*_%TC>JhRnN!Hw$(eXC{(N#d$(dznkm`e48;BRi=W7tSRX|kW7ayUvwFXv_Q{_P{ zOkAC$C>;T0rV~TQ0XGhctr4EukX?ncC}5h&84zDcn-DjNE6H<|i5Gca=@pc93I!S@ zrq31~Wv*n1dobKYfYi7KPA6O7+2X*YS+w`>vmj0o-~o-@=G;5=GjCWB=j4lqBUxgn zz%STDBLK{12Z!jFPE)`BT;pwraY)9+6Rpjiw;QfW*3ZtV1$v*Y(Uk)m?_5*f6Y#6aL75B?Wgx}ak!gea44pw(u~))w9M8ATJ!X{VzxYA zy2x8=3zmL+`O2U&wa6HT69p=XE}FkIW2r7O=PpVY09%Wt>HB7~0V7wP&oYaxOjX7| z?&t_=J`$-qyj1-9nF}L;{yh=iN(CxCiBlgQIkIdJvSz=YNJMyvg1HkC0o)orj2x?^ z@@Knp38|2wH`-j@6WCPpR`n z&CfFaeigzB$Y5BPpInA`G_Hr-LusdEfvskMn`WalsxHvxoMobKo1O!^hm2+I+!?h# zPVku7=yV__r&L4(T%V##>V*yF?9iaadupq{4WETSyDUX^G`dLs zIwhPRN9U*0JnC$fj|I83=pqcUQa&$B5yx}rBgoTb-11inI1$u7Ti2x%cV zdY~Mz7RzH-?$+9q4#Xk2N&e#vT0 zC1z##7!BU2!vH?c3a3sOg%9HcfEJ}(g=ZT%Wc>=hT9m;6Alw^j)sn;#fHE9$KPOki z4gGWPB}17+kvI5s-oAa#N&)GL_4dp#y1+2q=vdI0eN@vv#uM+uHn#kundOg7%b!iF zm)0ab%%eep#9bLVRsh9ZEFKI1(S{}CFH4DW3NRZdzYvte`SV)NdYF+;M@)tMc#npK zR4&h0Sj(NgCgBGtT-W}`Dq;YBCnt+bqwv}p6{`tlia1x;#OT&{`lw)g@=W)B&R;T| z6VF~vC?TD+OBgxfgY#xX+V=Q4tiZ-6^djxmK9K6LY{Zf5NZiv&euoaWD!S|D>6Dm9w~ja3H(Th>9w>8oeZ0wVRsx$WTS z1Qb3KtX+r4P`!r^&xKx2Tu!ly1?hbNg&#!zW`VO{gX&uz#xpEi9r476&O|0#%Qui* zSza7dbX2ktQ#jvA#lQjxf=EZmzVK-Yx5Z-5(HjA603X$*)jjr8DG7=xrK;Z5{g71NVWVhrs+Nfd5K4WT|{ zp0L_2p2)29{Wm_gEN!NeF(`uog$xw%V*82)STSwa{vgRbZ9`Hd1zQ-O&bm{J_E)7j ze9r6#%h!d;AI7u9_v6R|meYqCMp-6iBH&0JOlO*HC%-m+n==X392Lm-VfiDJ{m%90 zo#V;;`40bbpu{;|{zxx-v{THq8~!*}V^GVycm9$EWN+7DS2Ym%HfwsJwBK`~i!(1n zk+RteuB5@sQi=)mV4y(ARS29E;lt>v5owzNS8nqr%5&T-dyRb+E2LJi1FG^i&ZydN z@yFSxd|Y1GWmzg6PO~r{5s}|2y!(3~eE7h!k|OpM7P$^OG3~U4AMkhO5(5#=J&bXf zind0KJHj0LkcMv0J*;tVt%zIa01{u{PEQFz#l6qE<*AG(;ktoUj@PdRn4Pt;mlBc^Cyzt15jI zFFw4rWo-usPN+Q1vJ)RHa6H?!2HA5w* zNp|WDU8DZ$fEe%7+nC&9Vx5Favwr=f(InPm+6dI7-C~okN;7#a@knEkjb;n0zQ?m| z^@MB;!_LJ949%1+XB$V(e^rM8J58T;4w=9$Z?>=oH*D;SRnV#I;zV7$&TttB`5WQ@Xi{K%TP6 zU1X6S*X(BYJ@RjG#PJh(2S;}lIC>H5m4!=G+4+Mt6hDwX`yem!e6a1@qxoE?ApE$Q z8u0~a>_{s+zakv+V%}`~i7tKf6{$$1A=BHzo6W?rAtQ$ZGTFpNT?(z1>PBhpA2Rj| z`)Zv$V0I4Ny(TIESvTNx};sJG_c+)#FQMmh^LKG{u;zvm@NiFsyvu z=h7`CO7&j@Adch^(TW0lNJK~EJrg?R4lBB0!gnf)lc4F6|}{ncvI zPD{wnZNCGyYOP1LE|Q^?#9TJpyRBI_bIs%~5_6LtOg|-*FVR^U5ucmO7UUg&^2FQn z3H0z9Lev!Y03c*y!wU{W$p_8=Uh;bdVO&OvT-%U#m?ZXLniJf?Sg9ALUc4r{n4#=< z|J-EE`tP$%`W*OB z;XiTQ?2lM43?$rUn&MW8X3?BlljXBX|LoxH7LzQ(jMW?SOX4v#<^N=2F&uDdAK_&m7MGe>KhWF7uW}<_Cc-gxY&0Ok$t{>lJ1n)w*<3k zzC!R@GD>UUFDLA)L0^(sUnymeAp^VMzD2e-cR+i}WK?CwAdOw23sTu&C&t^Z?3GaD za$Fh}+%vD*38b#NV8QcCV<1pdTK#MID-&z_C1p_B7hz`FyI&NkL!;lTCuwH6fA_*saP?h8hFoxW&joXuZU2)(kL0qn=`&n@tXHV5~xgFSAV_@O9EYoA0R@Bk8a@B@EMkOYzG;3t!P153< zd*#z1;~H5Se>lKuQUCgU`*K}YL4$9+K;}%oewi1?i!bh-Kq&=E9Q+GB zg_ABGyCfJD95Vgi%_@*$r~mCU*qN->J);H#8}|Kw*9iZU#?1MDBC&~BJIFaY+PXXa zXO%E5X+{Bp6(d|RLI_v+JLXQ;d=P@IoLguXO_YO#{Bi@c=*Zyw;fIkQy?$oL9k?IO zQ7)=7I$C2)+sp6m+qQPcTjqK&k46*n@DYM^7cGnN8~WNoQJ~I>vwS{mPXzwl_GA3= zB6gvjt04@j5MBkayaf4IE0t)M@n&-2ISu1nae(amTG2_8ibpJcciEjfLBg<`S2YAM z*YKk-vODpoL`3gB|HY$eDWR#)LILaQC8GDeI>^|x3xTbKH~GqP1rAzQ=1~<_rBT)! zTiK-NIf5Pshfu0$);-{qwMH@AvY}q?_~(PzNRL+T-E?goPBg?~1&iI^c1gri?p$9H z&sXtkdi^e)Dji!BBrJb7eujB!5>eOmB1j!Z9ro-wBgF~lcndz%N3#}I(Vvs$Q5bx| zW-Kufr7GksLL%33N?5)Gu1zJu1bc|K(+x^uw8jh+%5RYWRRO(WhsDtP2U1S^A3@6h zTaxzwGE)4HB<=qc_3{1heuV#fF=+=6M_cp%hs~^F?&{>|;QGIGv$bl!6wrk+zRDOG z8R?A*F~t5^>=-hhfRT*q{l3vSEEHdQlUi8mgiSxg_t9T51VgD*(B%JNk0-q>JS$5X zV3-4Er*oz}XWvez{r=vc;0Mu8mlqh3MRCf>6iPdj2WQi^7>Pvd(r%9u(v}_HJ3uVK zZJS2c{;HczWU{~f*=2F5A+D>lb!^TxH{Ug*ztisd_FQEP+GO9^&|3B!C+##*W7w(P z%rQPKkt_sv8)-$VP8O=9MN`PxYHJ__%0Z6j*#G)NIh2&v4Zno_1u&i0TA0&jVHjd$ zn?6gBx1)bwr>9s*2KI;yo28DE)@t4d7e)~Syu(p%sC7Shbrad;n=;(dZmOt%76 zVeBqiN1TR`KjYL&N-QzmA!I}}UXeV&%DyaR;H(7%P7x0eIBm@Bj3$z6?iOO`u&@?S zFl6i2Uwn4apF__cG}H0MeZO@P-(U$cYoz4{zxt3T_*a|eWma8RwLf|~S%}ArNk_gIl&VUFikxgxnu$d82F|GoD8V>bSeqTu z_{7~|YtRBmoBer4Ac<>2#|5zDMK1Vr&?B!i%K!^Yv_@;MN0&KMePx$#dv%8SQqa>~ zl99v72EAx`1l$F2!F*;u2NQ^L(Iy63H;Fu+X)-!DSVO#Dti=j{O2>9@`dyn%S?B01 zo8mKrjAKYM_LOcql8FZ>{(+Pc52s@`3rt-rz%zVlg8D3 zUER&{qrcptL|fqe#;_-Zn>$P7v8+Xcl(eq;JT-7Zw0;9R5Vojrh=Hn6 zyf=m_rAi60JT0Ssnlv9=(SrB@y!7bKp?U^br=yrQ1;nbfQE_P?n5CQX$1cOdZAz@GMKfje)_s*o zW}@8b$eNjvHif#zExTtsy|6cRpqJ6z$H;P#78XAHrQtEDWnu$-Gz;W||)`2R+}4&t+se8t~6d!@}Umgk-#38UbHnkuXBL2kpnO{9ALOmJ7AOD(Jnl!!z?Qiq&R!% z9Wf>q=rRODjBfa!LkZbB$%Zkcj!DH}b1RB4zcPLr5$2^1e_n?D!f}u*;u$T>ncs5W zsBm$yRmF;B2FK37i?=Mu1YQ?tixCd%U~q){+g}vQo1a-QAf@4(waeipK+=bKYo24UQ{Am)vgA5Il}@H*^~5u=VxuVeX+a>sKZOXs#MwJ-JnqG zJq2B^U1>%e`RJH`VC5E#1e^f0zV2Sd>DEYMb1}^MF1vVAr8doS53~}MJfVxx z!`t3AlcMZku0r`E%IqAahqAnnULb5jPQhTz?Az7QR5MI4itt;Yqx-9P_XS_Z z%Eq8Y-5T~z_B|;wlhM&n0XdKPhQSKCZCjZ{z{YRhQZC9XL6M6;$9A@I8uT^JAlD=w zi)CZvkjM&Np=edMoW)*Z3ctJ<(S%t_L2((^{KM;VyN+5+=N zOU=6~TS}v>kh*5207V|&HOrGPI~H4TF+K06o%Prx`%=*83J5_$Ad9gaE=A}|_6ups zUw<(G49yAX65ut_o45oK2O9G4nrD0w)UE9VE!K%XoD{DH_QH?^dG)rB&6nWIpn;?p z)nvROqQL{6aQ|R?Ck47y)Rn#`^-kcTU^~|=S|%ab13+aYjbZH6e?qGrBkkLqxkKB@ z2mA0lW6LwVjGL$PqmtXdBCaffVI#3k6n>fSX3lntjzNq(WUTilke=fup8u$EcYt zaT_=zk04?UHBwnK3}>_K{d zhMYe6?Y{Qd-LV^8pa05RZ@G%Qp;5Vgnf2PJ4{zCN-$y*BdN4G)L5df zl+UZ?dC-3f4_yDR;oLBi4P-!$Vf$stHwgiB=`6FtZA|cY6 zcIGu*zQ7R+13Oz~=xxyTvRdOzu3~qgQG*Ul5d~msWE7^6sw1>QDXd6JRnm(egfg2u zQY4Imm6CzvGBV0*B&WEP-uSQ62LyyRh+Nd2YOg}k3gz0v@Zs(!Skr&G)eH zgHOMLE%x+zG)i$xp}iYm-}9AheO1c7Qh;&XG&gmD@d(VyWrYW!{T(}RuSDPLKVSXp zXEE@fV<-B*{c;SA96m48{a+OUa)0_o-;B%*KW|x^8M`VPxj4uh{S{`3{_WF$4ZbRB z3Sar*FCc!XDkFySfBT6bD9ggf$Ao1kfdB_vdK0SN;{!D+{K)4r&r77Fu4tCX+l6bi z+%AT9W+m^djyuDcnflRT-RjPg&g<>{0qUctY7vBjM#v~_>^DY~ifUK{%rpxaLWk{( z4v?nD0%(trVgk?foI9LD-ARc%6h~psIa5|jxgs6KpI~03PqC&8Pg|)`lqc@mPiNcc zsjdOM}@9jKx1qNXYnBXr6WRnk{tl7t}tyTiJDKHb2V6&ULl#;VAUxxFGxgc z5rVrDwYS$GtSIFxbeeqoY07x&4oVSWk_ywu%F5>6OWMy;yAkVJyzTmWN{xh*^L%Ei0mxs5+t)?ZLhCymK(=zTEj;-nLHvm>N*Y5nBi)w__-Z*^ayM~s+rEv zWW@@-bs8UXsip@m8)b`<69Ci^x^&C(MpX7@{v^iXQIX6&xU-Gci;e>6?2yYEK-f#4 zz~g&V+kTFs4j`fqEr4RRD@kSP$7zEr5+sk406=0(dLCKu>cz+QJ`Qk=!F-NS$ z6ftENa-1-OxZNyGlj&BpUe=%FI8ThjbOnE3$=9bGP(n1mnqM%JANj~fo0jeX&^=st zl)0;<9h?fr)2N2(0j?C)i~shOi4$NOn%1KFXZZQ@6Y!%F z1Vknz1V686*N)uK);W2%XtCA@c8@fS=OM?>%?0>C{@3qp{(_MpCfxr1ksxsHpsdU& zTz;$**jT1iE^`yjj490U5vP-u>Hh9)GYX|3zfRZtlUyW)LPh@3DJoo$C(Znfz;yp| z`RjicH2;3!^zR@eV&w3TmHqOLR)0r^e-tv6imO($eDK_-Y_$e!B<)`;e=x(Z^pQJK z^eG^~HROebgw5rNb6st*N!XmO^dti!;?9fb;Ke+B;en)Yv*j1q?vB$jb{??*T+Cnl ze!JL=`vqs)7XYRl)PV^)!M0iaf*VF^du_3%NKZ>Jy!#9UAlk`;G|F|Xrfx7^E6awJ zUDO}wgJ$3MhUxwdKN@XB4&yEe`u5%6aIDso6m2Gy}@!6JwZT_T41F=e>#}Q z6%(??zArF?j;>g&ZCV(6r+}ULX0)Td8E^W7rc>76igBSmz4Y%K6mml{WecRWqqzbn z(9NOyPdtQvBL#IiW(MxjON%t=Hy%?E!n zksI^ruDm@6Yk{$CTd0N|cr)=0EHuaAu`+U~W9IkoM9$BwzjKzG1pX|c z^EWbGu$vsuN3_9iis3~S@nGM+cp>RKX_3M3*bEsNJ2`EnvvNK}XK!`@x%g#rSge)g zhNU~M^;lwCn%WNz6h*c{E8_`vPo3bpDMSZrGi|?8#7-B8IDdB%aAv;N4kb&p?UVJS zAS}(I_c(eBKZ@Qp$if--qw^XhB|r=<4w(EJOHoxS{~;i%^GzI7{>gpLC8ji9vR!Pa zR&)*Ss<7;!TmFpS!pwa(UCSh z!+o8stqvKz@|pu4!1o6RNPV|Tm2k{#y_zjl-5OGX^Hi;Br&giW1rWh{o8Y|l+swts zT`Kf&thEldM+2$7u5NCyWZC-K{Vkp*>^V96DZWU(L*DF|T-U1abQ}ecL3SdSRqV9M zbJFdfJ34&yUN33s2k#+4`$#+=Sl*G18X6SC)YS{GVRosf&QuB9Q>7uq695+0X>~9B z6%y8hb>w&g_jwpPZbGdjR7u>Ck?UZ}oI}hYDEn%JS*1o=*`fB;eL@|ajq^BG`f~C? zmBr9|k#|O3?QdGkcD#g-ce9n1;x*~#q_u5?$89R%Eyn#d0=G^Bw??>Hw7|6)l}Wh?sdQdfHa35rj zm+@j8;~Aj}3x-BU+3bvmuN|Hb%k`6~oxh&XWxgB*%6!j7hh|V?xHUu>qKZ=^xaCM? z9n!?FmpqVSu#R<2A5&sj9MXi#aV7ndKAaKcJiK<*JN|{K$KA_i6Al+#masfXpUh6! zXX~nhiB_mSC@un)5-A!aVZ=V#WXW_eE1}%sF>)i zvD!{odxRv?)Q=rLQx!c}5hjSHG?jcoi3zzFg9bp08)ZAap(1ty_}b)R?K{a zJ{3ewH-Q67df2cV?yeSAJfk{;gw;wWSF98n21jb!I0^D%qJz~H&tM^DBU~~3lfIam zG*rzhyOm^3c97hLB)OQYs1Sv^waA#R7ZSDn#4Lc&AZeO5lQknfoenBde~PTU5ENYj zMhXd1%1M4$8QLIl3ACdmq^zU7#MV-fo=~EFcY2HsL*M6Oj=h2c$~jhRWpqZ!qQNEr zHLQ;b;J+-z1vk+lmf3;+9TGXq&;ucnKkrlEBnXH*9+xag%YRC&s9Sd z_}fuRaajwV)I@kw5ht+=nkv?*n<}IxUEE3Xko9dBc^+|1o7L7NX zxR*H6PrYiXQmNimBCUH*d7HfEF(}0+D{?X%s$0t18)781#X2`l97CP28b5$v!AS*Z zv5>aE+=ajg(jYwa@E~yLHG?C7hfnbv!v%aZEq1pwbn2l&XzGPUP}eI5r#5VgS%zCD z!1C)Q@BqgRy`o?1o*Zu+PrPylVcXRU00yu6X3E48P6b%eJdXg-y3h&(xs{z9r{?Ma z*=Zqw`rI!Tu}?#4M)bNw z4>!PS(v{#6e3b_h57h`b98sMz$!3L1A}5WQwSYUI$w9`xB%`3vi&z3q$mT* zE=HRkB=)EyNQ?LFAt3M|Z;C09rE{dXvWPr#*0F*d$~1qUPU@-X$&j<3i50%FO6o%n zM5Amm`zU*c-72m1l{LUXF7rLfY9{e&e5pcUsVM1^P*v922T0nDH%2Fx3@Wn5%lt+2 zB(v&7_1K`Ulz1!3TNERj_A$8?1;|SflQ%;r7KW@bXGK8hg)Fg+-S#BQ6=Dl$QEwo= zL$o!=8YLr#dbVs<-NG%FxmHxNtaZ&oKKMVag2ME8nSM!l>7548RuHc{v9>m{taFyQ zFY-69M_%Bt^+IV!QoCg9U-8(356m;~NnM9xL=@IL}f?8+%3x zRu>|+a7^-(N5iFa;L2+kenXmddmW1Kr@!gvS;l^>(#nt*UmY&? zPzmVQWdO9#2TMa*MUS8KXpi!DGh+rGW94{bn`Hr?|VU69V7vm0A#DZ4)9YrgR=40ZmL z>%K};Y+I1dTTGe>|%4O^4#ow$? zBJn>r7ij(j#1!rHtn7`g?JV^i%s$D$e;~0$xo+v6Pb8)RnW)Z(aD7%ecjR_maGkgP z?e5EVM*;|n1gjZph<9P=K%YPEmI!)rAR04$tYjUh_07TfYUX3~BI_3uHXFTsZD9a+ zSPa+)^fiY(;RAKFR0b?(0q))7^>?xvi4OSNp{rab1|}|pJ4A$H!pyM%ISw8ZGOZHT zREZ!3@B9hn?Cy>k!C~3c64i|{6QI<)KD<2f_IyEvd!amrpEN7Rc|*Eak15%N@^&id z60`3Q92dB^un!JT>zk>vh=tQu#zVz?)_R=YDbY)1JWp2xDp4F|nx}>B5bmSS^@p4acMm ztd>=~EuqR$F6hRvjVO>@Y4WtLwHY<9;rw=eNck~tu``F6HVjR9<4WhE(NRFXwc#Go z)Mb>2(A+vC`@@H~RSny^*${%H1NrMv4QKk4>Iyf9GPZqj%LKDJxtC?;IK8kW5yuI0 zg-V{AVq!%b*Ldm6nuNRxW;A2so>h-jIw_sNdO61H)f0K{!|f9p?!vul1HtVBaeC)7RXS1m}=o%pInUCd89U?+Z^> zxwrG+6Ae1(vS>?(S}`HuovMltVEG|H`4o(G>!(KoC{+;d?Ta{2IjT^qJPBp8yR(}d z#$v7lKQ)YlwFYsL6i zOOnP~7(b!bZ zN{^P_m!^ZIUJY79 zUUDuPKaXS!s%5EdP14=vU+;A#+mo3>Ez&Kg&=+QQv9rSD5X8N8MG+opc(x(fb_9#AaxJEI+o?y%(x2#Iw9GPy(yMD{faX5@gmf(ue62_4 z6M^_?3-y_18e3^3B(#YEm(lxm1u&Oa_SW~J7$CQ;TW!DOuO@>R$XE+UnKO;ip-H3EuZAV^DMF$1(`wQlI>eAY2g&hO`9}EKuLusflcn7l+&A1ZUm8 zf;*=rYI9TqIZjN|!HIf_oKbW3C+^k&NTC-a>-FFTom_EMa-Gj*(JCXwfX zp-)O?_+>KH5(y;5V(dspv0Vht&bPgyLG^pW8}kqW@Yjiy)Ft8Z*QF6%Z(0Ag|7h@x z0Fv^1ZUMe?#*A(2Y5Twj}eZgN~$E^4ia&&_%2 zKF*OyJR=+ z!7}tZ4qe{NJk}1op~^33M)W6}sUN!_vFImJMyGQH*O}}rMDEuun;@Nvpk0ZQ#Mnk` z4Kr1Xc1e*SCk(p}l^up^m_S>SSeYL4yRL(P-IOHbxC*2RGVZ)2Qeb<9c@X`ZE(d+b zX9o^QYNbBcM!U`hn4PBdWA$bN?n8Z0V>j29_5#m0e_Rp~UDG~i-A9v&f@KsF2FWXs zO^*bmtoXu|k-z+m6iG}46iQmh5H=}KHLfP(;`4&M zpKK8@Vy65BZx-B-L9?qLx^Dk`Zeiq+VB zV^l+cQB4_*pes2YqO;4@*n9*-Q8X~CZ?p^JR5ouNy}zL4q2qy1;RQ%2WFThkg+XM3 z9Fm(STU$|fw1VJ5HPLJg*Aq1ia>xxFaHQ9+rZMq}9+4j4oqaUP9S}^^$x0WTvDxmB zma*bB6sg~u6%;gDKuibIB+R9zR6Bpf!~X({Y{g5sQd)+4Q{tb$g#6BPx{-T1RSZAB z`TI*D8p%Yh{q#1F&z$t1^U)vu@i+S#HdoSH)6|?xlwy zr=t;1b;UkRR{f>Af$mWBcF$icP#dYm4|87+0-$(M4)A%udV2RviYgCp>&F~TIJbJr ziv||Ue-{G=LTK&iojP)$6_Y3nP|6^?LQlIUA_d2aPOmfMDdsy|!Al7;_!vv9qqr?? zixU??=Emkgaa61+(H9xSu3%`W8^V#%vhESYZliNt>*q#x=eXDf=soyVJzR6A@m@Yn zk3G;#Y;Nw&CXMRsN#D?3iiB-@vtZ8~bD1Sl)ifOH4PGFDI*8v4qF4P^nCOO~=I9r; zC6r;ICaQ)FU^UF5_5 z^NSDM0TjYEA}E<^mQ1_{4gyv7VT(6V%^2oqA4yl08a$h(m=qsC-7}WunRpJjZAY;` z5tA7a<1yN~MSn_^d{e3@bO~>@Z(!-jwQ=y>fj)sIE;kvI{a`wr*~wy_*$jJ5gCN;2 zpQ=Eq>KCsXOu_s|w~!K?PMz}8E0O=$E&SBYelf7Nq_sD9HMX#Jrgi$gOq2F+ulz?s z_+NeJK>5EhP<5fv5h^$ZWWvid%}80O44RIlC=oKQxXWhKEJMvY^EndGuTWsb@=&;s zFWw2)8)lU=7CWP3KOQI84>#IgZx_2*`WpD#bXZXC3`r&{K@rmTyYagMbXk+mz=U_WFDoVT^0O zpydW+!uPKoQ9nJgOWI%P5-nWw3FwRM5VH{7kb%o;?n#C+5>F_8 za3=6wTesnA6f4$q&*1EL3eHRbAwP^kP;6Dh6vS+Sf)g)oZ1kIH*4bh-*i+5^5ST`f zQv@ixU^=da7QS@y{~XSb@=@@>Wr@E*#b+bpn1n%$Z##uqnhlob-R6`*(FZVve~BN#lCS1b;NzRt+Mjg zeHM+k*#Q&YQ!O9@06NI;T{^@G?=-nPjCWBU!90O%9)Bs76<9kW>i&P@IsKp9>6@N| z(ZBW){%#}4OMMm>XkJBa>oavtj)8viyzort7;E8aXyB;b1!D6+1&?OvCtF@A>uL$% zokRX4EF?H@03T$ZJhFJfIRNb?*X;xs?ya%c`^WXyE(NZN?(TJpk(T1oR+>l3r4rrv z?yx5j(1lsi0ca=!WqGk!dZt&>w*;^sae7n9sVl}MI77B$N?DLWqzZ$a?{bJB%Wd_$ zbkFc1Y|(YPGGz4fuYr3HG-7O=3`yUU^?uBrN^v@XK|h4=h3sK^qK7ZKG9ew~;|9%L zzYK>217(S~)221KQIel75Z@|f1yisw9CYKT?9lDoI%O0fs4#?*3!T<2EWdWTO`0fZ z9qV!YU_?1d#3`OXeh90~IwtUa53hC0yg1X%9%rg%n^@tGD<-^_Ke?i;xAv@1(we*O z5(0suDQlgp8M->+6&CL7?t^mWg57|YIZARp_;Pxej`d=K!ez-fG>c z=$Vf(yv!WKmiKb4;*j4+X!|T<#Hp{6@-rw#;@?FjB z`G+mFCtE743d0Zn0{reT=K~KYCay6vHOGa72^fHsmJ~cSmBQy6S0qzvfh&wB@hvID zEWKlhRNQzacXr|q=uXhFm2w$$)I^5c;MTa1^Ze4g&ApiOINSTz8)g@@S7Z*ZIRf-n zIBcssk}!cEOGUlwn6dvjNjmMaMeVY2eeVG!OPfVj&2!qg0?TI2bJDo8MF-q&FkM#Q zbv~fuI8$J|h3SusA#yZL1UL1Rs1E14GE995E@z<$H9JQ_Y73BU!)q(<*t)vfwe8_7 zz4j1n^Q!H>nH~gkQj$cpDq^l`yoQ|gR(qXp!op$!1jD% zn3H2ERr2wrd5g@|zzG%;onrC6Q)qv?rI0A57K-n}Y;U^bTz1$X&E_z&H-uI3Enq~a zM_i@t0obO4>SK-$gh^BFx|~h-5vA-^Qsk4$Y*Y!6gp#c3`Oq#Id1r5)h(9EEsWA5H zh#3ebb8ro1$ILO)QbR2{o2-nvTB5h8#TOS8CfGZ|Tb(Ne^{UjJl=GuZD=Q{l;|yu* zn~V=0e&Vb%kiTE2dHi5CgN_*pI+ev|wWK6IY8S0GYJ^Ta{!Y(G8&5pS5MYcrtw6vc z{}46A>9yFJ#95%Z7+7yzh`a_Fu#MU{7TVAXu{L+xql#cG?JQj)X_WtR>fFI5kOgUq zPBTao=`k&Jn&kH}^Obfpp%V95R1+hCcNWp-bXHnjA_!gtlBYsR&DwObmX5w-Bg|@6 zVYF(fqK4tE|MlB!CN{T*+#U05Zeq`K=l3%nx$32Y=K6-cT?-Oq$$8owygJJtPU1Gr zewgx|5EEMcoG!^Q>+O;JAki2p9H%5o1u@F_HN^zI#@UfkK*+&#iiUb+HA`6AKOiyL zkzp~DU!$%Cgm6eHym}@nyt*YozTO9lLcLfdvBrVziI&%Iq*0hg-uxV!YiE0VjxZ(n zvJN8MWvc!Gn*HsU^(jpdT|YjTxdS-zAfIguCzoa|y=Mn~FU(`lce##SRR5HHJZT!5 zkT8W@v>`26qU8iLhzyE;gu@A$0d6ZS=6cv0gVNix{+urj2m3l4o8p9Sm-?m5N((p2 z=c5P7`3JtLVFT`#8BiJpMqn1?A*m!XQ_J*PShh{W)!(ki2Bls|F>-K;Uoy4~VlJw3 z0;7dbT%*;?=f3Bf8{Q#N=Nok9-@`Pj(|v1#sx;(0z7!DxqlrZk9lsrTZ2@s{t`N^2 zaKNT9-MC}R*`;mZR+7G6FsJ>J1U-#>g#QX)g}PRJG}3;a-@HrUh4fzed!5juxEC1?`n+AuY0Hk zZ-etUomhLk@i(^xl>6@fZ(#|)fFJkY67hb?j(CgPiamGWWyjovtH#}`_`ewwZvw5P zB|*JGy50&SVqkLy-jMJ$yWhoJ%B@5Re1mbD6m*eYTH|>f3T}~J)NXAXh~hqPsJ!0= zt@;J_I}$$S)GC#HqEm6iKLHJ?Kc&=vBgY~7H_!fs%dSlL>}%*E1zpAyOQGhcD;+8~ zb|{&ZQ=zBh8s=^F$&r0!L4WFoGkalUtOvejKz@^h#R3BH_Td%hnvAbGuD}H>jLG2o z+)?$D`ThBH748e1&7uHIrCEn&vu>WzP7nw-tJE5UZMrUz>l`iuhQF5ero8~|ifvOJ zQHYZ=M572ll3_H2LgobvzfQP_9~~n&L2c|MjL^*tW{^Od!6sC5J5kK!er{GfjJ$xo zmf_?#k~a&+XqNt0&4T4wE^rY7{H1p?#9{TL!ctvJ@2x?1>6eSybh?kNGk4b%cEWwf z0oj#br1t04oWGprGVwOiMq;*{%H)>6yLQmdG@Q3qmD$S+IS!u7z8+u$O#ms)UTKgbTO+T&hITu5L9-0HqoTim7sx2mka>PmL zxcXD}{rzkvwWAAn2*dj?42NkB*YWU~dY%5*s38B7!TnD$&iFrMUzt++#WY1`Gf)sn zD>G1`?)1%J!OEV#1Qdzk31pX6bud<1ZFUQV&rm!dM9}iMf2qFeokUMt$fAFaVNFh? zGIDa>RBtBp0_Z|zMf-yWfg02Z8)uGzrb;o8qz<~e#03{aBW-8eB=a9{EpaqU4%%@V zYdtlsE)VqDk3z5kNnJtJUN$|0`0x8CeaduX+(e=thq;;oMN%wjTqIH=y-?&yCp@bA z+q5>KTq&FbsolU^sV5J$Km$b?;F}CO8Yf~3=Fg+dL%T%AD^H6#d*8J}f8O{B23ue1 z!#EB)S=Nqj+23a;co_z)MkLt#FKn*Pr$O7%wzCw6uhMvgjDVc~%>-ON}-k zbHX0ss^Rs5u9lm;Lv2syU(avm_bQkNSls2 zN#IhQRU(RLC=uH86g?{os%>}Cf>_**q<&~?sjH`rtBqxK{CNT572er&91H2+yjEa= zZM>BVyK5r>mN{mbGL_3`9LEzbt6#&^V@#KVRnp1JHJ|{x{Jjz){0VpJDmYgl)B!$G zRNPH5z61Vsm@TTVOBd1>vy=c zVy1Ihe?_`}PeeaQ2UOIUa_%7T(XxIIw}vfRBYI=h&KusB~P+fzAd?koA{3IqHGBPMWW?s4PF zrY9%{+;nIe6&YEn(YoH6neQwHZN}^hmNzqRK|DxP6W;uT*6FSLaDby5SR3dPSVcX)15Y?SoShhGVi#rm|28ASAOP5+);d&ALDhEMV%y zmU?ILtsNBEMW|vV5rfA}pC27}i;>0rux0mf26br@;IfQ%;m;()_OtBt+LzWZl|az#xbh~?T+kax+JDjlIG z$j8=d$iYJl}iQ4gW4iz3u#r5{#| zwZ{s@vs_<+fY1!-&2wm%@3UW5CK!8NwRMOmQ#Ce%vW$+J7*xn~ z0pDbRjvVPK8)o4R%7*Ry8ysi!8%};0^w~XIhv3Gd^h(8fhQyy0>S*K2BYB25tDX9!ypp|Fb!*&7}tWAr@6$x|ZL5B~KRCzA3m zD)M`%9q5mA+#jp_e}iNHyM-q4n-K~6b%PPqM@3CdWyFCZy@d=FYvaeFfTr$zgtPM< z1$Ij|ueMPx@r5$c_Y9^|+4Kj$2kRDHVkug{wB$i{H|~3dUEnnJ^XmZ2+!>6oMAV zpw!9W$6u%KE`X}~N4<~qcmeKODy2(E^6&$dL?`O2uEUtpDHTc-jpT|Q$PWdKxcKU6lY;e|ux^VG$xBIp82EDhtzGtOZP^C9Yg2~8sfz;?_! zLLGA5Ww;%+;kH0w3sS>_;QoGlKE?&XqR%(q{^Q$ofBx@(?8X06=p*{4&;Od5l{FM* zWj}|hX$u1KrU=4ZnoVhS)h*E+@QFlb8J+a`xsh!T+MfBE61*&pHKP9V@i ztE=1v6y#f0N4=V+^!q_px01+a%6L{W+&bx)*7l#)ctd z(Q2F&<0mo*vM}z`EV!GLDo50MMq8`qP??vRkZ)4C<7yRJ6&)FpR`LwiMHL4|pL8@* z*+A~L(uh@@vWMNJg#d>d5HB3T+)us24lk9 z^T+m{->=(czWOeLw}#sl=A{@@#Y;PnKYN!+yq)UVyB4uej+nW$X3Yv7wPC&3#5=N> z2WeH4$tdw$=CU+!Vi84o5dR?Q#&vl6b+8onM!^G-u~hn9d+m$XR<|_O3)-0 zmfiz$v3xg(MiX0vN|Vdl#t6`Uq#yf`$Wmfcn%z~K1B8&w6Cf2_e4f|{n=a_wGOZjE8> z`#g-gklXB2t0@k=)CXFcD5_L}KgmjZkmEEJ{CK{BX`U9-G;CUW$dCMy8POlnPcXUT zM6Z4y?+a6}8S$i+y(sBaz)XG`G(A*iS^P0H(pLr|SKlz#YG_w}4Ffy_s`tOhb;;)(UuQH!dda%>k z;&dU>F=q!87kVjdCNh$&TLjoZUvuu8;7+vjI!Jh7KacDOr5F=Y+7sB*Cw!p}#HSRi zFJO;;$e84g-uP=;uqL9AAS@+0k48ukQj54YN1)%&&z%BkO{J!!OLxf1c2qCr%<7ig zYH4kmA*)Sq5~UovUrNRUHqhXLG2z|Ey<21BQey%|a2RfF{VVOSA-jq#h+ft9TK+M| zW?Hm{s{N3~ZD|>oOLl~P@~Yu;mMG$Tb+A6%)D8@L${to}_Pj&_dv zP}LZGfkgEXOO-gtY?zJ(*j=_x-ICGzCzGG@mA5B|2d~#5DE0B$KC#QX=%Ag zMVW`yKmhVgs*B|hf5ze2V#wi4q`3UY=B_f3wSi1DgA9vboOLGVDIeCivvM#XYf_Rp z63JZgDH&qPni7)6KL#4y7jl(`I$p=YM_;R%fkk!9wNK5;VOJp`Nzi<2TI6li;zJlEhv?iFVMOViv2S-;Vg+G$SQ^= z2ciZ3H)E&3YVjaHCcpXevR?q^bXVbV^lB@Tp{AuB-=(XMn-5Qz<> znwJK(p9?X~=Ilpn4)I2kM9M^-H@Ni={M>*(Gg*p&h*+e>gV$o!qNG(}x>&=}StH91 z^&1tfNmZKiZRr{XrO9-}rA+Dl3L-;at?N5ZkWNfRsoKrxJN<$P+4pfb^W7@g$AR>8 z9pATz=<-H!T||o`vm|X&VigB%bc(zb#w+#h!k&1Wjnv~&22r^aCeh(*M%9j_GN-~> zOC-%6t+i`mh#Ae!)-PnaTg9Agugc21&O+y4Yq)U&@T*O_Z0Cl`FgtUFUC8>MeQ1OC(k2Fl}{AS8Cr2G8| zZKos%`(eqGxKE4|n0~JjXi^^SAVv$1jUm+t3OIUp10GjSk5 z{t4**aY*ami=qDQ(|<`PjY^iE9tfXx4rLi#c3xT%Qmtqie)kf@7ltMz6`@23kH{N) z>ewB4ihTJ1-*JK)_f0S_^!EsQM!U9zJGZ3y_q2(ziwUmDv$3`H>dj4Wz%DGR0X$H4 zd?frE0VE5TJvm` zyo_wS5$Y}TH}&kZi4^s0Zv6{OO}Tcf1;8U&yM<*77Gw(-+esU5C9=I%sv`;`r30%m ziADiztFo2rR%v@#RSX8$3Y^QB8v3BSqriU0W1u7*GZlopKPVWF%-iJh4_eh{OIySh z6z*Z>4fW5hf}Y%i&=krO=E()DupzIMUb>4=y!9E|rKJF`QG@u$k+mABx}VBOUp?m+ ze#kr5sd(7RdkYSlmmPmlmYfeL{!e=bJ;T^dV#0a$l(Z`XuAFU^nT8Ma%-~OtT{m z!OV|6fz!JbyUXA!F8~w6pGKuAK)GS(H)?~-%pXIJx`p5dxhd*&fEn;v!NAv}CD`MU zs9Vtl)C^#&`aSFPG6Fm_VNxCWfV6dmfh%)>R44_UW@`3J=h>fQni9X80eb!(`nG|T zs*5H$&W(LH6U7}zoZ;dM6u!uhW%T^eVK0}n}{Z~&({l(7X@-wBK{t>4A zA8J+piA?`rCFZ}C9{$#S#+2X3qXp9`X#86FHdtr99NATTTB|9-@&P5S?9jC>)Sf z{g?9aI~{=oiu$cl-f!ihoEWP3iDX3+*e|h=U;e_L@DxwV^H3Y}vX5;+LD^E9xs$T! zA!&aVn`r+ZY3~@_NuNcHcDm#IW81c^j%`~V+wR!5ZKGp59ox3qand*4&&)gX%sbQT zu6sY!hx$@$)u~?{?6c24F}jD<@1^9QnTM2rDmMR>ul~~z5#il1-F)weLxDwtATGae zS%e=LpD0#eH)6SyqWPJ4V}%Pd80=12Rmd8!!dKBqb^cJl2yk59dsT7fV zX=M7_1EciR0D=~21~oBfwIfmVv|~ew{^33>pk6ixRK1D&JO);|VR>YNLf_oaFK;3W zf$PHN-;>1EB@*$=2?Js|;9CXuZ34G&#kM{GpgqctfDgFpSMMgBW}LCv0_XS+|2h`J zS#>+5?=QIfe*JH>;g54A|H^d!Iu`#vSF)z^n`EJl-l@T&3mze^9t-y_SQ=kXBsC%- z4VniOTXM6>El}kC#^oQQgzWnB~xT0}(v$}5Y ze6p1V>-`4(!FkgWC2-U9eP)Uw1(~7Du!FcxxbRmW$k~u(h>P$heH4me!+7c?+BZq< z(67kQi|9rH#p_)Vc~YU8oWIR9S<-jPY|SgLxym`M@KxHqtWiqFoGxmP+Y$niLU|@L z5l>?Hre)+@T1>Xw>crY{Y_=j%`39@kOiy@qWsScD@Z4{ZXugQ@bYW2>*RYaE+TDdO z*?+AX#t!~{w$XufRJ3)Vs%aIGs^X{Yb*$+LPT?Kva^yL_b$@A1izTzB|HUCSN>5#- zDH9CIyL?KZG2Q49RMT>%o|#fFajE2(iCW8oQ}z1M&_T+~o+{D07R`4o2IBMvB~#I8 z2kzb8xmdVrC%0Wji<6XYt837;vB9OPZBFYUliuA>P5Tf zF%tXvA5twg{iRw9W6*2#CODuw>xn+sYdmW8Ac2En$E?m`9nAaZi-{wbfWXM>EouN; zLCDV|`1FI&%pdhUn7rm+O8eW0*VzXKNXKV6ukp9DJplyLlYGH08TWAL?fq7mIY)I? zq|G+K>u1FA%I6JnSkmShkqkD#4wDL?^u}8*8u*2CR>nC`=0T}Y^t4V-5?5azZGuv` zQMhz;#C8zO`OSwXkM*3z+@0`Hd6E+)mI1cQiI$C$g>s_q!GRb~V^*AwDCx7+4_B-C z2u5W5T7glUxd2EHs$RMj2}2$q86z}&d-Td7n}ks^sj3)szY_*Y*-Y_5;JBvf;?&0m zJ(grbfltW*DU$+S3D8ds#FOKXt2G(UGPXwcn2f}S=tb^oHt0?t5M?}?EmO(nMP0aM z$iSGz=dlajMcuCa6qt~f&G?=`t6ZYGf_rb@$P!gdQO2%%V8IMZ zYz4R6*b-sMdGcsO4^Gi}QDa>ZeaNDFqDLEi6dcOCu6bWizO~ti`C%F%5+uB`^ck;& z7+3!|AC~(V8h5)C;T}JS0s=R-H1-z1fPx%%x-|9KR?1Eid}21W*}PS36l#6#Qy8+IgP8dsD;@?~ppR@{aI1mFhd> zaxH;dYyJousJgH2`6+$e^3(&|(-lGP`I_nO`C7j2`P#AW`8uKQ`MRm@`Ferw`TB|O z`38~h`Prk~({!*|d9*<%QF(0R1(CQ2fn^L{*x1lPc;S4F12z?r+VFrUx;=r|ut9hcd~w0MQ^=Yq zfV~N+I59!0AiHlq+t5I2qxy~%3!S2=M*3z!b#)7<_ASO-{3n3BOCfpo|5WM!Q$W0$bUtPzmQq)`qXz3Dqz(9g6;rPI4GLF0ByX&ng%IE zlYc_9Xtq1kkD~xwoQubn_f{ZXVKx$>@1gFp@KC*MEFMp)`0*?gvvXLibGmNJ)Ms>! zLl4rmenTYqZq4M>rDG@M{qG#>6oU*$`8KB_(Nqv58Wl!$%B$+8?LT)6Lr>DrWC{)- zV!aiw0KnWHMHinoJ_24~>26tXFazW#&SxiT1t{wrD>{4rYmkrwc;fcaN3oT2zv zG5mX8?3N!H9yyx8lWYYn;UPGL&n!G5Raf+dZ7tH#cB%i2=6k2FphDj7OuVhmvV@%2 z^l5Lj-TAzk@qTsb_2&M-`UA5?iENA#z27%BwR@!UvS2(?eA*nm9I~wrUoc1(q(i{6 z#0tuJWIreNl%6Q}y+&c3C4_DLS(>s$6F}Tv*OD1xyc&vTd!n;NZ~;KwuItZr!eBHi4$EX|K1C6$}`Zzf~uT4p0w`NPYdjX-ogq4eTFz_)g|+MfG#u=w*@2+l%Vw zozcq!nfDbz)_!zP29I}A?WY{5ewxK4a89i1q~|=eA)J1Byw>_eF&p;2Rv>$16;r9W zg5f^H@PVRfGSoMqUwwoYG74~o_jDKbj|k5H%e>|<1n1xLngm75UwEWfiz6nc(I#3P zDl&3F1s*aoe2|GC6C)G`J{oW0IYVdx@fkLocVK5PY$}^5)7AUPSNK7Lfu9^wXS(~j ztLszx0n`1$#RV_W=(ZRnWMS;#0JUCWz?6S;MwcX{tt5oKNOCLrYOlq|d&K0p$+{B` z&>JpgH3Qrxe@R!3jTvT%#_oMpO|H6Y-*sQJ0W(TA*X?i_Z+OCVrNbh6(w%L)M#00 z8$^{{*$qP=xh^_#M4(83JVDqcF8b`@Hc~jIY{rQ>sx`w(MFQ#oSW{onQdmvnPq9v6 zS{+@o$fB`Q{;P~lkoY{dSxYaAF2SaX;xbe)%ha_k=2~N1%7;26^Hbkek!;r?GT)% z*<498sJj*9oN!M-CW@=j?R8cmr8px+1c@4C?nN(AyC(8^SOACbpUbYJ2Gy3IrBd`3QqqU+JakT8Jl@ZZ;geHQun)%RcI=w@t9WZX zQ|Nj2s@(qh(kyUtMHs=QNtn@dK+QgjD&K|aiOh;o{b>-rVlQWSoOt(Y<3F`?@*oJ? zKwNTni(YeglW)8GO3mH_) zP(;fgT|@Gl*Rif$?Ca}XiSpTX>4a-Ao6vjs-d2GaFuv<@)w9npaiJ`8O{KO=&V6n@ zh3(tGCb0cl`H5&G?ifh^%v9b>DiewJ!KFF7C?u)SdXJpYq}Xd>_jhHahuPJ)`u_W9 z|LynrPo;RY{~GM{-qHL&YYhJ9bN;)Yz+caiG_`jSa(WjT{F{bYgiMX}M}9cZPhdp{ z_69@r{N{uZnQz?(DZ)l9+g7-@jnz_QAAmgKZBfe0)5X55r@7w5E_qpZ ze9+X7&W_Ly-$C>Ie6OCgECqhHWg;AGb*c&fltMF?p|e-&7TdfvEcOM;^h@ou&rcY_ z#z|(qbYv&uz-No-wp8+GaDp0ejM!;P0o}faQUMrSr9* zZbh?pZ<`cJ{#Bn9Ecq<#y_;F+os9Rd`s_aqNc)Em@oxtFcMtZo}D3H$Od)^)*-5*pRNZJKvv+-9P?#1KI@i z0<=yG7bWQNZfWc1wqhr_u_nNW`^J##9woiTE**cM zpm1Uuy+Qwq1P#Y+EWa!$`bP_*{8tO=n_B%*Eb~9V1I7P*$~#5jeQm<-U6B3^y@>H1x4LDJv=Fgluc zzu#Tn$=mrsGdn3eL^}KxP3yCJe#M=^XL}n4LO~U)O7JyF4Mzo9dnIWjD;N9d=Fh1q zRE}LMM!Q)KLTuxZjYxAhD}J_B`o!itLX{Ow%5U;3oJ#F%8YTGn&CZT$#UU_*LEcAo z0h+@|@aq0=-Y?+oHU#1IQQIs!#XURV&|Wmawza4WEO|H3pz1}q+0Hl^!ObMA-M+z7 zFfvC~;H{&;VeJtNufJpQ$NYhUU-$y&AHTqV&l-Pyfq&ZW-&6)7Wd70<`4nJQ@%iPG zfn>a&J6$>*4qc2yUI^UzO3U}{TFhnYz=>_a?QYo1JiyF$e;VWPXq&6GHp2#Qmd=N# zLt&F`wmz|7m>kctiaTfj{k^$(xYbrvp+lnO(m}hJQV#-!-n5xMqiIQ_O3Ig3z>6fR ze;AQHlw4btPQ)`Dr5XmUyk)=WV@|__nObQNEcn!7f@>j;gXKd|d*(<&IDEDc+s`1( z91SgS!m~6N@dJt*HUU50GGDf(Q1i4YsR$osYpCVRNxmWGZ5R~ba2S`+djc#51vRX> z?=HVvt9%(ZQrqu_WBZ%o{!@h!^}ilELp=w*Kc3zHe9V8h|L@1Ve}I1qp#5VqEkIK4 z9ppkvFQ^yK6~XgZd9eA&?-A^eSbkSBzZ`Miux-Zkj`j7i@OZelFj$)Uk>y?U;clTZNF?NXk_uOn)@H`9}zAF`L1Up8lW^-NWQ+wsg)(zs;eviE z9&9lNU;irGj{aza|L(kg9{@Q=BRki>JFf!e6+1)`IPSa^@oNH1pax_e@GS&27K_sl zV!KfEx(2~i)kcDN3pGrMs8!Bdt%L{%GS?uk#7g`~ITQ&8FZ?(+m|T2r$|qr?%VNj{ zrRyn~nLKO8Hy`7IGW%?xd~ zq^^qYP*^!_A&!zWR&6OGKw(&w1?Mt2$3K1+5bGrn&>urmUNc}*avROE$s?BurtCURh#no2o-Cb!ibjst3E)#s_ZvY!PMN6o3Le8t+>GqJ zjY=!v%cKxUZGJ;rgU6zki4Wi2c&mDG7@X1x5kk5#i^nmtC+|9%1)#n8*qhyiQKZ?2dbt|KS2_gK%l@e zIe^VYip1=b2G%2?Is|C@O-@!R!*B~GZV6jd8hDS|^4!fJ~(AlKq zfjgp8RDOuSpuRVaTc6TFUgR+Eup%6v8n{2Tb{&{H0O5jGgN`Xmwq0Tp$h>|4NxaPH z<>BKLjEkc`^>QKCUkT4`43_+28yWYR3L6PQO+p|T( zSo(OyDh|dhJcph zkX)-%7z`x14o7PX-HuUdGGx|NI>igtM$m!A^8@qesm`zDiCYfDXZyWJn+*OZ@A*GQ z<9~V2e}#^J(2$iZRS;F+yjbw?PY|LZQ7oy!7vU&I!oZPA1Axh#pjg^UDhed*5K&oL zn_9cCtLlr8W!$B``Mecnj9EfLMugd}1ioCXa!xQZ-j7SZyC)#8gyxDBdm$tAlOkE(_OnFcq;gW@irf}MlF54z z^R4}&)+3hEassK+lc2O^)E5?O(_Rp(x9?Ag-=d=>Wvb3#0$VBbd0Wa*#w8bswPjuOd$;Ari}Ult@bCaoJ9y=i!_o_M`05$3 zSPAnH9wd~2g&XY$i3Ur^we8IzyM8#5qOOw&k9A~icKb0hjQa2y2FuQRNsS3hV+rbGOV$L6*`_z=BnguO70 z`DwCn8M~NVKgdu@h_|~c*|Rm00KSmUgR6G zr)w+sYuNfWp_MXcp!f=R&q48}!fn+aOAj$+{09>_Z*JhMOG{xB+K{PBwq-vqR)L)d zNavob8oW1UGOuzu96LDgXFu2Ci1Qn}Xi{{HK^MX{gubYNZPG&=b&r?NAh1FrV$bR&1{h`NC7v|%Ryq*E?Rc2JS7910 zVfXQZ_fN38Rmk{0%!28d=g48H_;HmPySDH_zes^(k(gUGHtZgf=Pv-&pXNP}pj@Oj zK;OR>?#+GjIEnfygxl;d^ZFLPiGk_#P2uJ~8`ksZ@2Rz{R{{mKcZeSF$Gs8%9c}oX z=lp75D%n_A>lywHZK#Ol_9;%hOYw3jQ3hmUVkuK&VjsiL}i zZsr{JRE0OC`wyt^w1H1NEq;;qVl;(&f}PQReEc7)mkNDpBqP1FdWuV>}6B&u=R~aY@-EuoYo}s`n z@=@(z897Hvk3IK#cv`pPIT5MVcXg9K)?tFNd>=b|REa&AwN}KkLI&8}7ms zKm&b27b(DvA4r=^&f^i;r4?KcQEfAU zJ0Mm5lx3#x!#Vb#%AI8~v|%|gc=EUv_#(>4BR8>OIuymSli=o6j?WwD9`QKt_Qo&Z z)u!h4Epvh9rac>_MQ4w7C=Ci{jzk7u`uGqg3kQO0e3?YN_4vM137{2>&n1d{*K`iB4uvST`i(;~$!hHMt>w^?hHV zH0`jQ!c)ljT3q-%R2xGbFx7`1=y}(C`t9xv>v7}f+q;5-l!Xy}xDkz&{S`E-a}${a zkup)Z4Shtbnr1I|UP_*rjR3o}@rOYGJmM=$l9mfk} za_(Pd*QOb^08KuyYC3AxrwE$~;_bHi>_HRv$^0#bjZMGeI+Y;#*PB7aYUdH60)S5GYN_!iA3- zS8Xv{#~m?rCeOre9I-{{O{jK%x-k)9Zyb60gnQkZ@~rJFq*V)`jFe#d)FEpx!2?Z#AryUbin2@eG|Pf?gx#ZORh#{O^pa_SS{iP z&i2~3;|#k!oc5z{^V=+qSG*XU0Qc8fy2pw>F3)O_!@NwNt}wyWF3SBVMIO4ggOj-1 ztcw(d95Gyy2nq?#iDfuGQ#x>+HeZH8Nv>gfqlYVM1 zSUo|bg)K7fjOd1>2g2q$iG+`^9Cao^-rKZK?8_b|QkO3*{SpTXpG`zi{~>Kq$%j#x zE=aR0WZ}?GfhP$4C*%B;H@gQ#@Hfg(PkLaT!!Fbp3wjT6H=Lfr;H`yKRt%x1wO)~N z?#PLuXnS4=u-H(#wOqc$4LH#<9C1<^52IRz81(7uE2hu>g_2B^*4e`%CfD3ds5zi1 zT;L{lW>>g|C8P0z1cvZEV2XiraC(&j$pSI8i{EvDdh#j(+9%=R%SJ4^TG<0znPT30 zhnxxR{vPwNpWdX2XQk!CLfxJbzNta!#R#7Z2QE8o3PoKx3{6N5P5{;tPIUA9W-XwA z!uMHGf*zq$v~ddscx(*Ld+}b~-UtTRGDaUHj{AyjDN?TV%WI-XAI#(R!___-EbCnF zQG4v_c=}|9<9mqq&%0=gfc+&!KuAxJ^-GXN^^Y<34|s~$`+`ur|HP9b!vDF8X+a$% zjMPR>6XVx}k`2CZCSHR<#Q<=c;y>^d!pc?l-nPN6!F!K2+z%v&z~CS2A*KctjlSP} zrqAh|Oq6Kcx9^{ifVn1sXit$&s0kQPI=v%-f`bn%VTW*UJBx1)4J(gFOmUEZ0gt86 zX`M_RDfvs{s7O}+K>r)J%`x~eZ>h_N&(Iqs&jCL%OrET=_ZV+cT?2XeusVJtn)vQ3 z5oP~>0F}QP;jhZ5LfQP+ND?>sBr1>x9&A=NvMX5*S?IMaAACJHilK0)*7t9~pM71k z-zd|kx~I_JWfs2MvRc;Ulh4!u7}M5_CfMDr@78bcvv4~oM`Kuc4h2 zPX*Jn+%IwIGLG-#r-@jQEK1g(mCN7{)@)~HldgoXIDC-Tn6w$`~eGl`kj?e3TkKQ<3KOC5q;L%n^xuO8gY`x+COgzo&!z1sqX1!I4%%{{q5mNK{60o??xxU&J1w|&ODWE1 z7-Y+WI;4GAyt{VvdZ1yn8FA)T#l&E2Ifmrhl(3g_Y_i&SO}6>xawBy4WTDwKZtZ4Y zW9gwcCMuVg?`xc>WR$pi+d>ai zWow4^L9|PUY^*}sRV)%~a`BYH;3~d}FO}OEX4h9WXoYNj^R0w@nL=jJadfAoD>0*b zgTgF*~_;uU`4)LO1DQ z@O%Gx5*X}vKUBkQ|Y|+rlS(*f3CUK|XSA7F|Bs`PwJL)S(13<*@18 z6))%J>n3Ldq7t^3ce`uhaY>2MLFi^P%a_yAi>eI8ETq>WG$o*f|DX!zO%J?rvY=VC z8eztDg*P#W=qlfY-jOL7ec*QJ_EdT%!Vr7`)xS|%xPjFN8@T;kwl#<6#fHSo*Ov2; zi04(0;0?+YCm{5qP`VEkdM!zz^YO4L>YQ8=D?$&c@s-~20>*Jjq2h4}KK+MrwvUh~ zxpXIxhUv#vdI3@cl&j8Pcm*vMZW;f(cT$7=6JGHLr1NjN&Od(4_g?=yS=_6kqP-!# z;hG}%qkK*McR6iEDn*dbOhEKsiJmMq676hO^)6t3{A+UBxQe>RHg@3J$jSKJH8W)` zrCq19^CvJ}z$5T-v;<$jAKMuY1)3DzN2yeL)9dMQ2}b;}d|z^qC?u{gvN|b+#p9T( z4FO}5k51lkocc;0HUVd&%`G+Lr2z4g8cM2!3huG>*ESjg#LldPNgVk!9p$>HXA@g}4;1G*eNN4MbVA+g31XyW%l1gecEZnm!??TbzGP{ z?1t`I5mRz|tiPLQ2IIzo`{^^p`M!Gmedt1-L7Xz0$Q{ws@qz7~_%h$sasEzP&v5fx zqpKp53|JsB~?dRDt&_rff!$#z)v(L@ulTnQFYYO2Qf3NkzH z5qo+li7(Y_rDJ)9Uv!BKd|#;mMs4W9L@|J6G?%H&G!HfxRKcuO&lr#rPJ|Mh!8nZ~ zx|-pGGw%xLH@^wA(rBA9t&jriTp^p~1SEIQIgvB_q$5faII1mI1~K(^E7mHf<9YU;QG76r@oTdy7|qS3#$bD_B@l3XlYK)+ zs(9ci^pfgA`)ACdM+W|yQL!Yu(Eg9g^2MT$a>oa1#dxiQzT!hqK(7@7?-D@|W{+73 z^qk7wbFx$Yv3i76^~EBb>7rJV==6~hXsY^Yv&D5&Bg7HztBFb3DRCQY$b zD)d=|OasRjmMMD==CeP4PZbDm3|wBlcPF>sQJ4SSUHe0&`L{&qeR1!<<%WMdT@@;4 z@+-nf+~yV|Y>>Jiff4auvrB4L(7<=|WWh;@a*}oFY%!);Vj@2H#1s?FT*G;O<>CLy zlJcw8e33MMlC`|}UQ0-rBDWnL)QY=oKi=+qQQ61)^X(C`3u)J>uextcWtGZ4ZtqJ# z8rW*NU0hhKT3Bvc8hv@A!AIBi6}U^fP#B~KUy+X;DAmJo3h&r1Zrds)2G#oMO!?ilm*j}+auEf_&BwwGt~(4*D@B7C zt%wIl&1_|8QfBII2|X27l9Z-V9a98nq1|1&frd=f)e;puTI@`QT83?`R5&M{43*|7 z>YM8FOA2$9cafBLM(0La`q0+or(7hjUJ7AuUm;)`;zjmav5a8?)5(ASi4v2rud_lz**;3+RS zCYAZ7{Jn@-#2z9F!#v{JV?AE{8Oay9_A4nMErfBT3Yi;dWAcdR8eV{4D=M_@bV4-n zRI55_y>LL2iEu1TjjQs%}U?ZGxY_c}~BSiB(C0*!FTz+hg@^}a3AO)H-H z2|~K_4d+mc)lzB;L!}s+GGpDck z1}BqN0&HnF5mS-NxSD+B%+Ra2Gz=mqfy@F7kAY)$s~lU3nLU$4FVv7c=ZsiDF0Llg zU)^GIjngg0#7I;PEn#Yn2u4`&%l0qoTBJ2Sf{N>J|;AzBUXi0bAANzP+KvSQJ@ zlsK77sS#xgwetvnaE|{3;6Fh5e#>B^eu*}LgxPY@VzWBq6-a$Tg&%?lejP+EK|Zuk zZRCpcTVFwNupA)?c*qwE_Pc8U%zZM&Gq;c7CayJ>8VaOpL{BK0C<%HrngOjLvp7-!r9#|sZ051aiZOi2D=03$s&eL#9E`&vkAI;{3ez)8 zJrZV$dGc))Q8R);F^WMjo3^WkAbB8MDz1SgcIG8;NR7va?jGNlmi`0?<;CZKt6R@| zbH%}@xf|bmGu(KT-+L28W{<^tlQVPkEAJ)2T7wnc4N&31J(W8ygc;Z&Ro`LfjZ8^T z>s2xw{OYFB6!PP5HXSYf!FBVyhx`QhColOw6wd!o7wzBKTNVH0pC&}i^$Y+9W`Cu# zjZX>Pw(Ng2Km#J{g=8L(f;{RHLJMa6!fevtY6 zzH`97^)HR{U@#1t9QCh(nA4JbwhDfsrA*AwGj#bWFoI-Wv{9ygXDgrx==v0dFxwpUAKqE z07P*pb=qucL}H@>=mqRL`+7(7;AfHKTG)L^RCBJyAFE##9Q{biVVt5&c?wZnW0YU4 zd6rV!`upQdS`wCT(QmXQHkua|p@?3X&@CD-w=Fd5l3#Qg3=He zRE8!y8qNc}!g%Y94kWMHV|3eHa=0|iHqiqeBa#=F*6I}+;#1PxB~)BqI%{)9gSoWaR>@@zHz?B9!Bn78NvzE%VosARf*nLFY~~L^3cW9;U#r zJ^#*HY#lW@CtMlffw>leo)^)Bt4=MRmhYuZc>K_k;NKEuIB3dHn;UXCx=Z^jtwie= z_wasCD`)?|NCf_8TKSLWu)<%gYAcO}3dIJX+=uUmaTO9&jPwJ1FL;4{hT=#9+k>sY zc-3K^{EsTpCSU&1Xjw-gJ`VbF+Iz%)ka^I2;5z^I@c4uCYtW%Oo$bnJbZ3fq>NFEo zIvbThWJD=MYQ%fA(*r%S+_A5NHNoinIt2tAUexPF1k#y>UUW$Ce(Y=`IQQ*WIhdWC z>rex@tAv@LA)LDq@AUlCpZIFVWR?#(SzLOHCNg8wOGb1og96>MXU{ncon(}9T zU(MH*Su6V7L?RHS_YE(!dl|hbhP1)sNd5KY%Cn?*fU1O~?BREnC}ndbNG+>k7`_eY7t$OX#GO=d8W|@&)REl610_qH(4k zpOHRCN{9@&jO$*#c(Lc+{4MQae+s7ETGO(>QRErMvON?G~Zxcc_@UZOI0 zfXCB&E_w9FT=IV?^8Ft#`B#EIPFJ-rO?o|da0Ab$+WodFtcJ8 z#0AldreZd6^I~yKlVKJkl^AN`#O$VI&gx$_fp9i`crHgNjSh`;14WXzM1Wdr^(hm% z=9=QJGV3^uJGDGpjiat7-phN452RaVWT!r`qMD?(etl91jiSLsp+w?D--(D2kYR)p z{D2kJny`UV{HRt#dLYTLLNUN7OzMpjP|jGOik zm>G?aYt^w0@W_&&L7kWrj|C4JW) zj%RlCGC;P3-Iq|OHYm4HM6%>2EcuZdL(bNi4P7O1D4MaLOoS}3yv3I}$s~lJv^uL0 zLmWVGK1G2nz;Jbj)J(Fos4+jUB!oDk;uru_nNR*Bm4k48l5;~AMX-P-hrH~_NGxlS zFWSDABJCgs1piwXA6Z#~tveNM*|cQ4a{TS1)P8+zF;#GjWXmg^;d&yx<+IQ*m8diP zQhM&chpGMp0p9PRi)NG%Ru2MEl{hL5kR??52e?aN)S)Qe+LjjI?lzLPy1R7 ziLNx2niYypVG3GO`X@qf2SBS)+%UJc|KI2eAs7lvD2Z~~}NB@p$BMn;CK_OC%#kXMm3 zKzM|Iy`cp;HSeD5*l@_^Ba z?yckUfPlS(bi>cty~F=B*s7c9;}Z6`w2fWj&pPd-!q8x0u1NbS$P){vt$zOSF113} z8!oZ^Cf(*Ex%%9YWC=2L6e6h80SPTCN!`v(Tyt9UQh&&n8Ylcq?t(=fN zoM_?O#tI*wjcI|4Z*5SrIe-L|og8EIzYUC^Eml}9XR-l)5;N7!yPf8kIO-~-R z)AcfTzGD_kMLL=GRshkj7F8vHW~B=E8ez!-JQfTM`txop$h_-g>o)KX zRdx2K@?hNp7+q*_8D@h5(&x1N^noQHwjE^qS!8?Uwbk>@Kn5XtT;DovU3k=FU)^so zy75*YCEO6ZTELsablt$J^TWOxVgmWCi=Ei^w*^|wb2g#Z$Fb}}qd57jiBv~%e1%@p zwI)d8hdRxLMtMeV;0@?FP_68h(KF^e{1n_H0A^ASfgwPr?>IU=zC|0ktkHDR=9AM= z2iPgbH7%5B#3q^U^#%&+aN_>Ra?9xN8&S9Qy?db=v%|JYnn{ba+GB6=K9~k1wk`KdSo%f%}G|u1xikglm#a7xL3R_?-Y)b$pqJyyae;)qv)= zwZ55NZ-IQ;KnrLEPSg8)!nTi5SZ~`>-nL~z%*En-x^7TX&HF=LM4HtZnO%i~KDOR` zKff{E0Gt||j%$>??CL2hwY#MV}hBt0PH%438XQI0TZv%71 zBr%AQrt9Rlb_dKvq75bM2X_%CU(xNqpilG|!R{3E?oi5J(nUTnX5IkOei(CIh^a>L z?v!N?=y?x7WnN%i8@C-Eu^&#j498V}<=rvQ%tXf>XzH*SzTZNdB*y8oj`VuD7S-h~ zm_hj~71uS4fp~k*Sn&U-q)qp~TjT#1MdV+ToZOHf>5=>o9+MoASHCa!e5L}RWbz?V z3CeQutwwaxPf0oTm#MjYfF=G?Q*VpI*z33D-i|BtfshFeO&|lVQZjMC&P_IUlE%za zPMAo-bu8b}FK-AWhk2@o;V#?R{^*WG4;mkjsMSKTML??-ojcel8Nn1cWg?D0$(0BAKd z^myiCm+0k! zHCQ_}O^n5y>SLi?ts8e})*4`-hY+nAvz z1B|%Urp%-=5%wekAc@9wCtX^pxvEqv6niqbyuAyW(riEe6zySs`}DGSHl5nuWf?|I z*#=2iQpP|SCANDr#6Mzy0TQT>0K<@oR+W)PE3l;)c{ZPE@(iFHZXo80Jy4-|wB=7& zZ>8e)h4jpqHHp#GZ9-aB*j355sJBZ|#+ey4QI0UkkL-y?$6!wN5z4ngR2lky??)F_ z#xw&J900zlrV2TPws#>LUS*7zNM_3JpL`J{1UDV~V)#Q$lQ0X|oe?nbxjF>D+8wyz z8n)UiZUIbl@B3`_8Kxn%Jgw)rOffBb-mCx9xbC26*0gjGjzO_`g-*eT*fS^pYT-JB zVHR5l5?8(8T#oGGSdBkaj1e^YsHnn}ZZ^eOx<`9TuLlf?0MFv;>#hrDl{z3` z8FXX6uvcrOJgDPLJq)0>^_+=I7cQ*BnRAvL<(YLce~L#Gx}Jy*rEhf;iI_@_V|UYh77S}SxKp77U(d}7Cs_Vq zUAT6~&tfZ{Ydj@%SFAx$jw@}QuPK(Qli8NpPe_H`bPKR$ejHg6UchyW0VB5n$)seC zgVe}0X77oQe)I)2n>kkPum&Kdn%o_8(@GqYZ6?BCf8qe87o;XNnz6-%VqcxIMTO$f z3VY_j*~Ayvo1HOY^KK&!bWjVeY}P*z8+20dF-|6$izVxWnO%7B=3xYY`btL`co#Ar zvoU2`%%F1RKN*l3CZZDDYE#l1kF@uYVgX4CyrF(Y8Wvfes>Iv-O?F zHPg_b2`EJd5vT^vSq{^R6;Op}O&JSJ%$nAjta2(8u3*IGy%)I+x)nIHXF-J!3_{=M zw$8lK&bnV?e0kl-@&$x~l$uexT!Cy>WVUsv zIy=g=m3nd^D;VcwE@B}@(9U!0*!(QM$OZdMt8K!BEC48J2q~4DV;_@%I;!Xsy zcG50Lsk0bKLlq_2*q@GJ|Ar6Oc7&ATglE3Qpt7GeD@3{V>eetjiX*#2Y+qWpNO3;**<;*)^wDzV8y8m^RF)(g7mrk+kPzS>u!Q8e zZIx=l;0GSZsnaYpDb&r2Ffvnvwbp1*)8<6TqrFH8(3(G+so28wQC%--25B}Se+uFx zbyWM7yW?4Ygw~6Wy~8E})2dWX8083k?`WZ`(A)U_!{kI>RF~|yzhrNTU`JiX!60gI zKyFfjM#&cmP~2EX=QCPcC$`VOFocCAQZdS^wp8vYJ4)gc+iVF+EXH&ov%Y=lkjQk9 zny_WB%wHz-DjRw0q9KWbZ90*5Jlo7XQYQAhQ;wfr4yM#<;F)t=ZTxO0vuw7$bJ4UP zG!oFE%{{s#SnJ+*_c1`L`QS7zneLvE_K0D&=E~n>ZUM-qs)9w15PP5c<5AvO@?82$ z|4p;U&|KpyZpMawYb2joKXkH?^qpDb!KPMQK8sD}#1q-Z6HZ6Jrn;H!w?;UZ2@%qV zX{hsC_Tz()(`&#bmME{Es0@#g495+U&jtj@rOyRU{%H{wACli};3a;HJv6I_Kh)Q% z5{I4z#U32Z{L01{2!aR%8h8l;p%O?s7m765C)iuAD`>^#YFLsN#R$BdFBCpZBx!TF zPB2)GIA`0d#d!Y@Wp5c2XPb46Cc)hug1fuBySux)dvFO(A59fa71e#+dtckuUQ5`fOf^8EBP8OYL*!>Sb8uba5m(P7a2`o>xG&$e zuVk<2_|W&Gt^pYbx=#RKfIcIz-Y-BMGZo5oKuFmb$OV3a`E+*6Pmg3?Z)l1qZxVjV zL;CV9CZ60ja5nrgL{vgCFfomw0fy$3&feL^FtL!|=#mt<3_IPt7RKg;=?K2GE~8TP z!4LBxRhIPONvB)Yf4Tf2SnG?T*iXs^f;X5CgVWdPuVE~i3y5=w_it4n-Wy1{D=GFpE=*Z-5<*DK&JOW@JezK+?FaL8lqr85m-d-!zV{v zMR78|0j?-N*m3M2Lc;`F_%|u@dJe9gccyvHby=;?wk9u5?iXuq2ie|t=f8>OHM&92 zu+6?6_GbpxMbelRPOGXYs4~Wee5xwd2qqkN1(SwO#!|`f)^T`F!()U^=U(VEWeGmP zD#D3S4K*5f^^s-~nqZi9Y)^j3-s2XN4X(PVsG3cBNk3^b$}-fr=qtBj-2Dv3766x8 zHL1_y*5vsxuzW|M#1z!JXR8UMepO>2=WFh(uvrMwC4TbwxemjJ^{m#55^4)I`Xl_P zYkyjAQ#`XQHd~DIhc$5$_fo-33hXm39h=;c(hT)l&zLLN8=<%$Xv84HOs6wbn3qf5 z_mnZySUE(F&+H~c9#Wwb&%J8i^iA#_x(qTdrgjOEa+La&V9_-bIn8xvTeHx#BTv|& z4#L9tPZ7#mig4_;d7H_hE6w?vRiWN-^rO8Dki=lt*yqN&y`(ZsW4{(>r(E!w*6m2j zr8};Peng?A&W=xH&a3nf%slyRuV7G%eG+z^%e#ER6|WEgUW9Hg;OYo``%R83zLBPGR3o_z4cf}I&OzZoE1Mo`|R zt;EurKPJ?0{e{D%KQw9-Y{Oqk0Kg?g9p)Baw@8pZ@g!I$J;d0SS%`%FJl`hK#u(L9 zhP6AKnSHEo!Z!$2r@#jf-w%cym#r26Y7%I~B5y)E1V5e7SL8?Ze2&QJ+_@|=>Astx zkWCMOu87zcLOEvii_nUjg9+voQW=a$u3$~tthYit+-34)dFV63RzGCxoyRoY|J|jg z17rmSQ6fWsbmgkDBwF2*B(%YQ-Bnwox#sK9l{B20NzdoyT~M(`4{qlz^31`8 z3dXEG7N{r9Xx}>PvW}&=%F>szhE8b}<}IkX^fRc8=xEZbjn;V}K5CSn6zM3*h&CdH zaxs>^x-{lqG0*fnWt&rU87GXUM&_;W`$mX*5ulQoUd;nzUgQzCy60 zgCm6dN(j3t2Fd6b>4dUHHa6~RXJ-^gxYeke-PKp)vo~lAnIqr%_*%Sb4+HBa&?s-507avg>Gj7>9w zhXI7%%rQ(3D29B#{n7JDejE6KMu}_^u0YH$;c-25DBhx5s1L{TQ@4D(zaH-??DdL) zG^qCZ2N)QQKCJz3-Fiqi4Inf`28!mXi{Rd}HSBl>iXXpn_IlaW$OhWFe(49b`4F3F z@EOM@!+;ylz=x58=6n_FTlXF0T_*?)9hY|$`KRQ<+bwJ2*U%Bih!0;QrAc^)U z?%GgdIU;?}`|@Lqs<|&y^P2~=JXVn#zVe>;Sq_ejg`}RF({Kko@8-KePqVEO|3LK5 z-`e#5YbNByp%wi2?rki8gx~!E9Q@CG^zSbIKbFnk!NGs4S~J258*PK48Kruk#mw|q=?mq}UfL7vj@!`eq6=Y0BX{BLkD zm@-AFyHO{f(>COqzk(w~Fmfl=b3oT8l^1x0Tg~ft{nJPxo#)?}m=u*-ivMqL@E?Ne zKT$CM8dNJ2R^;9n&O^;Vmg0hfb!&GpL>B9LstV zZigUj3S*g{5XQ~*iL?#x=h(lcS(-mT-MxJJ5LS~M#!{iB@GV!4U}g8?BJHQ=mGd~c z5EvE0+EFS;W6pA*^Z$>UU3r}FcpN!c&S#|}TLgEs2W z<1QWBc~SRxdkYZ*ZF8)wa=;=beaGiGMD`FVE>ju0#?yW>HY7igJ$#fIQOE=GZMbv& zI`&NhEM*21tH4bhJ)l5g-<-uH^Bi(B@7A%KWV>lKL+*05<164v(!9lSG!Z-gM2-9Ye*&j~Gy1Kly z=Kbj^oCyy7+><4h7Y0m2q~Vug5H3@=>c>cpkrGlBN(x}rpyqzXi?5nkV-yz{^$=BU zS?BL9GT|7;VDtAm6!d#y^nY%P{o(ojD@5*px`Y2>!>a;;l`$bGkP#t}a#Lm__9rn% z*+}Z&96p30)3PO(DOF!3Tyz|q{QAHkL@a`tCl|gzHi?}585L!DH1pd^Bt54#JI9C+ zvKC4fg)xE`yLl74<+}yT|7F3p>^E7l7BEwhw4;AS&;P|8Ks4#r413c$08lz4SdK?*Fkd_y-j2KhwhB zZv0Oat+w@F`a@(*9nH)2Me|;<1F2u#62lQ@u&0uR2sJDUHg`;zqqUoGR;3%>%D_nT zHs7s&4LVJ=OLRUz2xFKhPr^e;M~Eq@bLC%u~uLmvU78kY9_1?T9xCt-h!)dr=cg-L|*iW;on=*5OE|rI)OoxSHW-I0D;D+Uu zwpp2W)cv8Kc!sGVpchFFPPYTyd+l#0R#$<=FwHO}@)ZaOjwF0DuW0KKHjFRNtl$rI z5tS>-_8>s6bRI?S)VE@@$Zm69i`L{{3GO64y8i|8I@c9R)WM9+%jc4PH6$@gL>e2< z^VP&QF)2^AIy$awzKg(DOf7PXz$Lvv>LNibC#Kw_GHRN_04tnjSV}!`Au076X8*@! zca!xxq`G3qj{-4jhyXi`s==S=l{4iFe8jJ4Ewk631`hivY8eOmBCymPgA|yzla3zt zurAq&$0~U&P@8tR8i$BsCg+cdYrat?+w?ivM{(HmhjA-DE44|tIi>bfT=CIOw~D0G z1$c6bC6#Hs{wDMB1aI;bdJi!0|He!8zu7#n{%bnt@|Pr*^ZzeSl>fde`j3C~o6XVE z>z`|K|1@*kcQZ%yyGz(lxVD+m%D-)xE*UQLir&P~rb<^r3=E|F$ZuC=y?WM3tvDA|nRxu7*KddfevAUt#Kg z4->qbr8&(JBav$nyT@JK3s_D#OmV|xy=t~*^!nL#@mo#`cBK5uAe4gkl zz`<9#*n+yj37adenTmV15t*^mtg9yzTWHat7N*L5G zCj6U{*oxl}-k^Ux_!IjZRNEs@Wh@BkWM=5%THxz13&xrK# ziUve`q9&EB)Ho(@O-J=o(hQ1$l*2Yy)?!L|;qxIponNnK{~X$r;inQVDhhX!ugO4a zK)>ff8l2z9R$S!_p*O$U2MTpX^1SjN>QRMCj`k>2Bo>P-uxWy4B{K(avG5T)izEkt zC0q~1jVX%-=zT@}az%lCPy=cq3!DKfzJ9^{mUsQ7huuWKj&L8|6$F||oZLkS3jb*bi1F9`T5tO_PWW!c@qa8zX#ZrzBBsBs z@ZJ1G-urle+g`Mi?t5Dr(@$>YtY*69BhEIt42xaR59*HYxRS)a0=D4(bnX8 zJaGS@w_a^lY-IX&)=Tk#3ridme5iuqjDuIN^#fn|x9ry^xJ}B>Xz_zoc}&Hz`dLg$D5R_$T8ICbq{;fKUhfmvqV*_jgo4^J|0wE46ML5g!)p% zgzQ0e*}HB}-9BrN`-1PNP7zntojqNxS$GiiR&o5KsI!2G`FSULNW~9>eF?#CWDz6F zhfYl2xNSi2I%G8p+MHve-4}?ui>!YsJ8tg5COn^{O}SJkN0ZsD?FfL}@%Ual!LXR( z$d0FO%VG{!q0oQ+fVGG-ZjD>_14;}??5^V)T6jsDQzA$PO_A;q&WWOvX1Z$P;WI8g zEn7_O4XDwJl#p9cBV#w#=r95UU-#>{Hkv%olk->0_G9-#DFnm`rp_g1kzc^EJbh8J z-a)On#aos?+@Q$qCh-R0S|W-cOSI1uS$A3%Xkm)Wg+>pTo2E0X&nXpiT~Jyc=chot z#lXzK>hO!`l(|7ui4d8tE{w*wX^7GzYzPP??ZKIvpaeSaa+GB{MQyei{lcF?mY}@l zOJkx|gx=LEX6V$TNtX|t7YRs1H-W}fbFeOZgt!^rPf8naN-X348-uMN7B+tUp0C{f zF<<%bV~+p0%KkOyj85O-t1z-!bCoIQV4sXr7^s(V*URN!%Cy%S8CI}F01MWpPhVWUh12#<)(aFrp(!pwlNx3S7)w`HVnN@ z&Wv};`YpOieXbTv)l^-vwFR8EcDK*cXh05YGMD&t*;Upc7t0x!7?D!d#+p?>0ZiSX z@1)*hrN2%F?MQ;Qp}h~hqY6xnyXPFRS5=QnmunLl;r4@Wj2PfS&pq|d2Ev56g!DJs5jjgT6YwrtoKI8gg z$IMO#5UfY$IDS%3Ja8)f!p>dD!w*?~dBQ*D4>A$rg}F+ve7yzz2I)cZ%GWM8O6HD# zKeP)IK3uB5`5cjsZ|`unFNg5yW!qhFkk#sv3)|iZ_Gf|Do#P1Cee0goNjpg)lnk4k zw4!qA=I-QA-un;7xpC&Fm+&RzP;Bo%((-UZ{nnSCwiKxTEXUdB~m|1lsAW*tDrf7eHm?g~-|Ag?G1q$CFp-Njr(Jtf|ga%-P zqXY!23BL@g`!i}2DfIRq{U8N4Vk1v#->jNce*a*NwTo?Di6PlbN<$PtbF{Gw#zTnZ ziL8=$uRW8;)s7JT%Wo_JKKc;poj%3sdknU2m?7h{_Nn`qX?v6d;}^2G<&C|i9gTi( zz$cFlt+V%A1pkliV8;Kuxb*LI zVGZh*$~fZhgq?wCMz+CGjC?{22HKFLSAuf5gKVAOuaI`*I2dwZU?|De}{0QHXl zWIOH0V$GaqNEU!Co_CPzeMGIKD;L#+Q%7!&w8pL?&)spswI|IrRHB8JYDF4cvC59z z!DH>h860`g1 zg8kKV_F5cl8QQF$?IoQWj4aPaZeM!BXCgy8vo^D>1uWm}vE_SP3U|{dW=iQ8?QDSF zd@V1hS7eNK;RzRAytaIL<53RsP!Tbw2vt}SsFAT;S_Rit5pDIt{@0lfLsVKTCC_3L z4dqblGFM%!Yx@k5QM(wstP+9y*-rHL*^6JKNn3->i+i?;UMtlM|Dwj0?h(+{Dl>L{ z$;xyk+`m(AwfO?oXR)5Tpdrc#%Z(Jn$`Y^KBc}4I;yYE0a;=G6sS^gLL)R?R{#R3D zho$LF#Q^+S?c7H2)geRC9j9~mSqGz4>e=UzNkUBK$@^kW{hQSSA6drB3_LA2AVtF7-$dJufm*v zf|EzhOxI4pkZJfa|G*VPk<9hfy#;o2{3BK`phMA>N1M5_&czkA`yqzcJrFd(9PfS0 zd$B|>{+Dg>scU^+X7DacVqbU+wA~26j#Rt$FV+d%>EFp8RK80eWgsF(?5&xZ zbrD)tBhaQur|+Is=JF~UAbcctEf!tY>cm)Bg}>2yHBcgKI;99UlTnG8qe*h+Z)sRS z>%bFvE(U?-oJB&Oq8|`C>FN_;?~?f)lD@Z$dsfdN)afy|{F)YrS!~!{hpg1s&$V!i z8=c^S!?}S-X zJO(RSmBE*@Y|A?UBqLHh*WH-gZL{M=6^ezhP>bmYOQ0(L;&YBxlfwDnhdn_ntIP~e zcazUTCZYJbl+F(y)BTIeupl^!9&k{9Ow@wdN+=!o30l3^+#JCyh!TVq38)4rp%m`U z@b^z@cTXiS!zLv-16y24xauQCq}MR%=MdnL0@k^w&;qwpx$xLr!%FTXGm_WeEn^WOlBXJjMf^Cv1>dP&tlfYQlrWyld7W;rU35!) zK{v~7idhgQ8+5=WN>jMVkGUuRR$j;Riph1^s5@TNhypZ*l9bDmuc6J5qNG$gg+$er zf=1)cF%V~)_tl8#GEzseyi-`m`*Eg-d{%d_Zsi4fhWm^)_2Gm&d~FUs&M*{L{9PHH zDkUvZQfu8vO$9eCj_|Fk9e2(fyLxk;AaT|Mu9|s-qsZfmgmFE$5wEt3Ay-h|jl7f# zjpRhuXPmR!SbtmFM|2bBHc+QvoHWXK`}e+xG`#;K<$G;F{zs_+$^YAX`0r-w|5ObB z;5PdAv4z^-`*kM>ppk)DAIL~vC2*FZ6NzLJ*ifa6YJjK^$k+28T#1^e{i=w_NhV59 zpL|2#H|)r=_Kj!Kex1hhsjRfs)!;EOdkpaVxU09`XF6Z3>ptfAZ~Ow=gqQL?9E@W5 zHse#7kft0Tw~w-#xbKHwm#RKYQ!+$IuZxaGQ#$oCI?xnsgXu;+_~I05mylnh6{hhwC={k)TkmcLE!oA#(X+A($t=Wkr;4OBJ z7n8;rC=I|{VLwaP_;y`&(hLjYs_=D1)p*^JrrY+aO~EmHDY=(AqpE+3*?PH%e-Lqg zuo2S;MlNKR1iFY;&H952l!OkU)!Lt{e&u`eu= zCRzRQc6xL$lQ`ota^SK{(O0oqj=H$cvXWIw>Me4sh=VdsB#Eu(bE|b4ET(V8a)h!H zAK)lqEinOP5z^S9j-tIF6;>L(!eFs1sI^swAQ{k&EH*pbSWZENzQ1Tlj*UY@=yu2B zZ1y`EuT=oPq0+@t-45Rp{R|XJ{EvRE6$%{{-Zjj-9naDpVXd~3atT(lBrD%WnR+i$ zP6Zosr1)!$(VMVewUDPq9};!E(JCywL}>N z_>Tt+vZ2M2%;u7I8HLKxv>36&W~!0o#W!*fNQt(F^gs>OhxNpwP7h4T4`J*PcS)+I zQ7S)2-Twr(SB5`viArpWvxr%!%%u(-Xov5(eTXk>3qf>JTYOUl(c{Ci zFu7qI2X`c%vkzk-KDz9h=KlpfQmtUrMd+3}BDviLcyWQblnC-5p+N1W7!N}N&Mv>@ zm=q`iyLg;TZl094W58FX3Ej8dZ#soGa7rwZ9kx94ty~9ao)|WIQY{$BAZ3{R&?{V? zNG(~#^eho}nlaD=u~^D51U_42wgNmg{{6WuyEiefR4(k|21n zu94?`aYF>=Pfhdxj;sAg5&9n&)IU0Es;|l@;+TGH1~HlDBA~%m+7`8NA6r1JyK?8^ zU?g}W!23&QvCN^Qd3fEEao_0EYTp==GXoN3_)K+hEd)R%9sm@;V=D8#0 z77V#VdYF?8hJig2mG_!P?v2)w$1G;YdK$ITX2^8qrCiuqqeWWX)8;#aZ7G|0mHq6Y zWp8^Y9?LW0)d+KsdT(XdDvrjnh&a7vA10o;^{JMB-+MKNc(O@a@Ow_1-ZuNUEmo4) z?Jq?7eCt-1#-C>W(38U*!dFw0qIj^rmQ{cTLK=!dx+EtNCBG~}64+~9bUfQ~{Qw8wM`X!wGf5H~Uuh?X zK_N_jiM>_Z;1}zWe6$#0@eL5vqTf=^o7ulEI9dyMvA*dLe(DeVkiO6xVO(xG>-3^& zbj^7t8^`U28#_JB>;{X_iy_&J-Swl#T;Fh$mg%B|%--=Su3tteCs&1hCAE&Wh&~Ze zthJ;|wo)zR6TJ!|lbFprJI9)8xrJA^uqS(9e%Gz%mJ5M=BQm=!oH&yz zn_f^zohq$mM?MrtR=iN?poRkvukdYh6L;WmK1FCJ?Irj3dT{-Z_27S>1O3CPh3#!z zZSB+yZCp+NcIQIn6}wphL|&X?H=EUkU(;r7MidfYZ<7wNz|qKER;I`pDU_io#*>DD zC)*KGF~4$$P|dZ%FbSwwfarRozOmS=d*0_V*>7eXmoAj#X2=Mt^$jmfTrq!zkhW>^ zGV<+~AttigovUQFN%e?+HUoVmfjuliA%h8nayhR=q})tSk!eMr5Kl>khy{{1UiC2J zD>fCKq6?{Te(0#caYR{^+kqv0xu(45mnV?DCY#8Xp!SafMQBsQdi@Q!opR+vYGd?q zoq~KEb_BvWN8Mhb!w6;?Px$(r%eE^N9($t9tn_fCW47=euc6vOA{g-a;*LB zU;7fo@*e6oV!`J#l_jmVP^NQ8f)}+}IWKw4)FTE)lK{nLc^>{ld2rnZsfthNdi;fg zUU=`{*gO>+y}!0IuHRq(=P|VCpNfG0eHQ=g_kS+{RBWyPQZ%w#VX;-yt!T)wyKb;b zkFZn}JW90?L>v*}hW3;Bb~2Vs#!Nqdl(Q^=Me)}{`F4wBrLM~1VP~fEdCLLc0q3Ob zd2Eh;7l_A~d7`UkU|cC>oMNJ*vLJku$!ao?5kNB;0d6V-OY_F& zXsP2>T}3^ikNwC}9KE@+qXKg$u(9SQGF=v9KN#0+cSQZevbyWr!u} z;iu^lw>rJc3x%j*jR_J-Gb!!Un4ZU*?~=YkF7-B>WLF4%*2q=2MxqieEPy;vh!CXD zl|uWpN$ROceNwLf{RRa38w#Sdiv?$B37IJ|Bob*m`oK>jW_GhyiD^+C?8|m}6_MyG zxRymO?m!m?vW!^wDmg^e1iCT}`dGxz{aPf6X7I{k)F`NhjG|D~&9Fu24k4Q;n8q|e z%xhS}Mi^_=j8b8%`tP_V66uuz#hN25D+z}{bidzF^r&fPex7&N<@n=dmg!IC`X344 ze|KI}TSL;kci;6xhKY9wWP=tyfnO8mNDl$w09er2wvTuxN$L5<9-P7FhDp6^%cdcY z%eu*U0I103AWp|(T)p>l^6rep0nGfGK7h3aY?SVoKsl@ z)Y*{AZ1h<)4aeFuAJ@4Euv~{PSVxj-(~#_1*4!}T<$v%l78rFVAA%Y~@FwmJ){^Jb()gp}To!(iQ z|8+i9sHUy_&I$BufejKBiF-eRg%V0KV3{mJDDh@rfWiP-%enL;J8-dIPk=x=hD3N+ z{s{k28h<%0)WzfQrW7ITSCQQ0$S08Gw0a&7R~NgDma3OUeu($0D?EkD%Td0cVqMu0 z9|4sIKz~tw*b9;H#31RlqjcAts6tM1kw}8+l)#=S0=lF0Q|0qFyayFg*qmWv`dCh| zYiM*#qjf!129j%SpRg0MCbk>WcW(D+8sTDMy}96%@no!Jw`NV^{yXt^`uH7Klv1DJ zs>AcU^;XM^W1Jpj_3otE?ORMZH)nGMMTmSN{nFb23mEKS<#;Cy3t*x zY<3z({qhPZ^R((TKNh!$4AFDUD_(& zGU?CunMQ?NY#^&Os_o^e@D`v$Sdw4mEJe_;eWzvgG^wuzrBC5wm~M)M5Y@2q=J-OZ zNMlnP4?I{YjvRNqVUH7Zou!Nh;_7~>ajqtPz^*b>=*|nBR8*)bFvOyUjhNlUj--&- zqi2By3ScKTp0#B6mOJ;X)Q{S=<4q!a$i>csGGTZ2sbhBzuwz$kM~2!fN*Iu?hh88P z%&`Jk0E800y1k~Qm*`bf4rBCV2P`(5Eupfo)(kcM3{N@YA^YV^MPs~G@=ogYjU(B{ z6vwan$xNZ0y}uTDdgn08vJJIY3!o&}oGmMC$<3t@dIz67YZ^(V^w`$M%7piD2i-8& z;nI?79#v}LuIDW9gepe7%ZO4EnM^S`kY2sUsfHzPMa2Qp$f_cC+pUIPft&aR6Kb}K z5N8hRyIdtTapoR(;L=NFPvV_*z^{t~<*LrHTVft&%pV2Qr=hE79)itW3((U66+qb} zVC6oUt|MNy?qG2T`>IaivEqkm6)#mm)n1r6mQ_Kq?wC*(CfFuyN1O$C)6#?2jv~07 zllI*u_$B=kmUUDgc?Zvx^(w`oX&1?@2} z2dZzSQy7of>qXyk);}kji8wJ6pR)d-7ZG#FlAAYo2jXEk29gK$PUatI!et<$Z26r z_`0driZ6|0)e8Q6pKR~bUOR;=s}MN~ys76n{FWcg-sx)RI2@NfN|rc)BepP6#jh-1 zJg$_?@Q3kp`}{;`o)Ys)L8z(CDbZ zS&YO$`dO9<8%rY3lBY^s3J@^Ahp50^n@#f7@6R9m>sCWxh}w~a`(24ZcJmc4h8;q7?%^lU3M4c~5Z$d3@T z%M1KDbi4MzXgFMQ5BVs^u-TVXb;3=bXt)8Tuk9^AMDPb&U6M^hKY=rTh7N%>xL}jbN<^Mk`4Rw*ep%OdJ?SlA1I@vg zUP5Tab3YP?MxNk2d<;2qN?HTGD401|3!QY^ChMnz;C#i7%5C|t0OP^nN}F%Qu;@8z zcQ~S7yV#=nyK(t>@UYMd)j78n100go?|-0p7dl40#Pc-vsF@?^2!2*q+%I9_3wCb) zo{j0r2*wjnin;RRSESC)HL6ioA{&X3s}GH6xWpmy{MTzk7Lf9Yt^t07e$>WDE9kb# z;}EM?ZU8$Rm)I6SJ&yY}V*Q4(oMs_Kxd;APhbyx%zjXIF7;#S|JdpJ>P7>?q)dp1K z?6C(Jr&;VW|8aL&t0@OxJ0??!{a05@c86@=5aM@4^XeQaVNJy=_-~B0E{Fr}d!m)~ z#~KOme}z>wLsuIYVH?YLA;rJz@OfSc160vPd$ZBFHZUQJK!W}+gkOL`P=PK)s$6-S z@wkW*%wUj_9Y*#)YQO4=z(G;Cop$)%t$SZwb+NZKHMuuQ-qE?gY>202tz~&$@842# z-_LcexPSVtptx<^^m7n&V-I8kU*4Ggnw-LOCTv)l?-z@IXo5MVXH3EYrDs57yTq_` zVApAo+6&sJ>$1)2$6Pr7)j|D(H{dFc-yN5KVnP$B|H|OT*2PmUvH#@Y#sR*1(be%Yfr-!IO$Km(tn9sSE{%6quI&ca=8sm}Y_$p-|$iv+9R)n(2jJ>XgO z=Z4QI?JsUpe}${!*th<-qP(|rxhQb28cRd6th{AmNCF!GGWiD!O<(ZI#D!}QE zax3MUuM~n!%4@+*AMSQoi|>&p8EMC1BRlEyBY>t5!Sw}lxs&UJ457cAS z<$h9=Q;{n=F_9K4I8l)nD>}8xFXd*&f28`G9t=nn(xF&nxf!D zNt*Hq7)_!sS!LwglQKmiRabOkC0&Hv)55P%t3nyM|Duq;wJ#mSoFUC|7z_&y~0DwpeJM8b}+e6w@9N`sf(FO3x4WsbwN$ycfWlwxz0YmettrMV_L|M|$%^)Bh zrKHR=F$I4BkYa5Xo9U_PT~b$5RX-*zCcQlX*a7UXBibV?etUR(x?NY|tiWli&I~kR^<9@2^(sw|tsw!(vS$UvdeXhAB;97CwVu!R$ zu!;7l5p7RPdCg^{0Z0;*&gPX><>b1|Y#H~OVmlWQaI)c*R!+h;Ahtz;FQ$RulKqk*BkupWTC5Vze zB%xF&YhSszocZNg<`yxBOFHXJ{h-A8^_a)CQ(iZh?xsAf?CZ<1;qjKAYi(!E2zB;=o`&^y9#Qb5NdHx#( zXGVfE1!qdaH3g@B3C6=5%>4TY5xX_Y@rv*&)$fq$SgqCr>K!Swm#RO`m(N?j95)=h z`rUfnf=k&Im@t#FD>{8supj=y);9rbbZ~Zz=XWdT`ZYGEe0}fWphWxic%?^ds2 zq1sOQc63JrG58II*nyVNQL1ajL1TI{!%ZO}K@fDYxSZ zUUIVS=9Jg#u2cT?OYpAnEpg6M?NdZ-VR_Eeru8jz&Qr@%i2SS4>j=W@T=nZQyNMS! zq8FZ|V@etS(_GG6j_)!3aW&s9`>lJisz*U}Ozi9VNS?#=N ze@Hhp_-ipbAZb^ns!UT&r;*IuvxY?jsRSB*Uj>x9+-X1rZPGZ-Ea-hrN09RE7!%*(+T;9y) z&2d6ucO+*(VgCb(v6ZG^u7_T3Uif)snALn_o)mZ%5kZD*=+EnFc;oN6-pU+CA%P51 za4HT&#qUsmrM%rBc-Q$Jnar7|7AlAO^=oQd{&4>3Xq~ zI92FjCu4uYm%^*fN!;)RaV3=P4n?w+xFrehno3G)9&wQ4-@7JFSR7d^BWlmG8`=ui zw3n4spxQ61q+k${U1u^Cnkde@kx7Q%iJk;9gRu6S1_*&$6R#xoU>d13KU5I771mMF z^NFdaHc&b5!$n!9?alz`Vc13#jlY*$jReJiG2^sGF@!l&-vLqmc+DEbr}rd|h8SD| zxiv%oxs1UAZ5nM?_-QUFU_K!8xGZlwvsAQBCQJe(;I%fY@1~?~Jg=96==8Kqpu5a6 zz-j4=f;;mMm=^xVRu5G_OVgUX5h|X>iki@FFLo#aLg-x))Vq=AxapcS`)zh^joQ`{ z0?bd6u_cc+m>On!7GHd7bc5sdBhR9!;Z@YY<0~LM2*>;K3><-`-1rMNWvQf$28ICHXo)#h; z4Y%Auj{jt?jubhC$%SL&npc<6KUW~IkJHpME2uXRxZbwb(=!F50p+XA&PZYhTH^tCX8Pa z3$GM|Rsf(QqqOS_3IZ`>*V4j4WqQcrX{O;H_{nwP1DA)8ARArQ*e%;$bRu;^R7r%`jNa; ziB;Io8q+wUw6w4~LrmN4RG)fM+K;)$N-ghJxys@d??eqJmpQs1!Ixr+aqG_h6okJlQS4SJoZ=sx zJn&36V!`-cUgK1BB>TCzHFBQuh_7Q}nTjQ--4xXn!jjb@pVDt(XFrY)G$$97H3Zr1 zhg(_fCJu-z?~InE7->j}Bnp>W$Tu`2>Bg`jdz})bNhgYNJjRnq0*LP$I4S1 z`=Tr6p(zm&MPX*XQ#KzG05d0`qoFdDgRPQWe%cz1%$yp|eT#SAA1azP!=R;yQ&Ckn z=yxSP*yS3L6)3ht$3csZA-}j-H(^;P6loO^Ng|17L9eac&&uAG5=XxQC?Wj7@`^j#9(c&4k=g@aB}voByb>96 zifu!oW*oea04E>}HmHJup0reVt$5Y17LYFJ(Ii&AS=W=!-!g)F=E21Ja zUJn2X4U8nR+{QfJ$n}~msiLZ8t8^>jNK1(^t(_d79(Xc=kt7Cn#zD-)wI^AY!PS8z z5nVvkk_I*)Ygq#u1Or9GFUERI8-FgmEn>G`nu5)fdf*JOn8bi33H-Mz7FPR7?HDYhQq3*Urs` z=Cuw9KbyIhf}P!+>s_E`jFOtzT|g@?{|jMQv0|OWE0_g8F|Jj-hl6cTF!-Aw`|uGu zXO^ZO5-h4(6(o2s@g4cE6wm!bM7O(K5e;;x?NosC*mO2dub0>)zdFX$Lm`7v^4`&# zWwz*zWYsx&Poo8e zEyJL!N(%yK(0JDts8SArnwm{wchV1rYXK(?DO#~Zd<=kKfGk4x)DFbDsa3G(IW>dF zMG{}yg7s=nf?1GMAmCvm)oDF(#$FG2Dc1xB89aldRYAK zRy8#~a zmVGAdaB`pq+Iz;Jscr?^7bf7Dy#?p;2VtBNIOJsmVVpcT)_TKb2Voo_o`FRRHaxeOQV0l~ zEr3nS0s?Cp)3yQ_Ju8N@>@gxcMW%El8OoOSbEJ6Jz&3KKNU6gzlub7yAin}q+1!G; zK{!q&)nHyzC_~ot0CQQ#$~YT1zKD*wEM&E#FhaYXg0*b8ycOE0p-ogz3`?6!%Ub`b z5;39*3~Go8NJ~yY9js}YC_5|`p5%iY@RimE8phB&2h#PJPXSP6=fd#o0xnd3@rzUp@bT(D}EbN(! zEl7|IJq|F$4ZNFoc4|UMW@%%2Dbx*q?^od}iT(lz>hA!Nu+BQCAM_!vDXS7Jg^kl%m(|tw*jz2oc zI27TWUkzLXu7zsh@&00{=RWex_<8N)LOrVJ-axyID%=Ls764e5!do`5aJRlEh^sX< zRkbMmw6_oHXKJn6#;#l5KicRLQ>Ifq4`bT~JexX4!KQkYgG+i5gxlb$;5D*{MYjA* z?9f&}2zLfGc1gLMnChSsQd|!Qd3fX!T60(OwqFCN|Egx-?M zD3+;Ew9NdQ9C5`!KO*BEB;aKfz|38$y1C(q{lQ!CB zHO^_#fQEYoAfR`3Uz6g{~=i8hq7k3@P4(xN~*GkcmFB}P{`bpH#YbC;Z&cAjPlwp zGvpHT$o9i6`Y|^Dqhb+r&32Rz2as(bdz?hRW>e*&BXj(OAL%S}(w-073Es|$fK@z$ z`&0IprFiX}^fPb%8ywiY;z<>v>$$UUYJRB|R?rqid7c?mCymZJhNoAfyCattVQ(8_T`Vy{+>+4#9)?vR48B=^G>Y3MdvafH!b@z?A96k1qd- zw5TCyYj~#Np-b>e%=`iE_4D5Q*9;`)Mh(KxSN(%(Uf~m=a-x3u`ukmSjaR57YRP(r z-U#$nw9C5upRV|9*>*!xx}4n@bO+h@puxNmuZ(LuXt$9;zHz;vuju))B=18QukJnp z`EtU=v$HZ)vt+P5xxaC!?^rRt(cYWsg#3`6}dgk~X zHmGZ624N8m68F*Xl%y+zspq(Y&Nh`!xTCci>{+Z>K;6lQ)6$=(8# z501hi`C0F*aQVZxC?BUCMgDp!)(OlVo+bmtqP#i;z1)QOg4{d`6Mjhu@};->Ma;;3 zbLTPL&$}qEFa`ONcJfJ`m?<4P1^LptTyf{;%5DDPKS5J`qGf!x^dWk?%;O!iW$2?+AZ39uChos#j9rdtG@+Xn<6gFjOuO2DHlP$Yy|GHGgrki3ot%d zE=95@4-4^^g4+V(n`HNIwTn$+Wy)4$7<3Lh5nwC&=zY!HiykBOUAq%Gr2@pkMUsZTrlZkdH^; z>n-WSA-5x60b6FF9xAb zBZDwR2wXuG!CLrZ$O*r}S9U=m!DC<62{9*ZT?;{bSarxs=!a35ZNVP`&#;_R&D%i()DI+nA-yqkFsnNF22AYW zBb2ee63_*n=EOa|Q&^j8f`rDrFj@P@=$n`~MfZN*_=q1*^`?;s+u0MTmOu{i=nd%$ z7r@#AUI!bLSi5E@K5_cfrASc;*i6+7hzEP{9F{q`d2_U;?9#GyC43UR^p#R z*j?5l&)oeO#vV{=w&2fSJxt$3S3^!&LH?UE!aT6ox0>v$)rFHwH5rpL5kf|Jz=KcN zt?@%+$^>u>j7bw=ow-F&AV0D+AKE|#k~}{PGJ+HgZ<3cXmN`OVk}2MXJ7EACx}vWn zC4_2ixNkHAQxWu z%OE$z-8JDej5`h)f^7Ec}wWbkOU`p+^;{&%NjY^3!OoNTNZFin`3CGsNf;OLYWeyfnLJ{ zPKHv=+8VPHx)Q^2^_okPaHp$!u7~taI@ZT|si=>l5(HCC-jMOxS;D!=PzFAy8e)D+ zHpCtaVd;bq7WGcWX4F0*R(UnT!sWCU;}a4)yi~&r>WMbh#s?ZLuOZnv*}tP3Rjo>( z(+K0)4CzaBK+<@EUYyuiSqxSDrjir_$PKlY=0nWdus4MWh%nuA?D8gB%F$9$5RI5D zIvWqe9P4CoJ4RX-hN)Gc;ya95=%rh(vc6>Kcg)54SHS8JN9# zA~{e>b48_$NtSwCkE>=YBb87qz-HP<-YFG^d3?tgmK>91aC0@rbHG{K$S1PkJP6{s zmNS`6f}M_8xM`jVt3=``5%FAb9GZxF!{SJ4Ds*@BgUs!(hub#PP&w>REQ_Q9 z5~ryOp8;ppXLN@>lVt$s*o&m_op#8yeVJ)l$+!>=KXb** zpMg{qlsWQ?vREhSWVWou`zLX-8hKl#THkuhj>MHYnh#9fclLC5ND)pKXI zL?ohSh;p;cO8d1L6cJskrGl!{f|;sXJo06-X|HDJ)5ZD~JN5$*agee4)&XG;zZn}q z9|t-+)sk|KgH?eqOOdLQ<5*BcRMh{?Eb zSHyT-8`1)};gV9(meUg940^_YOC18dri7`4AU~OBXl>H-7B7BiM1z>4+g+$kP&Iy| z^_XY`d&G6My}9GHOs$iQ!l0zF0U(T7ROeh=>r~7iNgCJCX*{B_kA8#8?2BpR8sW`b z8eURqv39n%u3)E{vP@)|D_D`4one=DWbC}MM5s(SxY86?!1~|_O6QLKN~K}i{to#q zVw;!0z6||QIz6|33V^@g>nm7Z!!iA10d7;q7${V~F|xqz?Je-Ki%lBrBG`zc2rvSgR^0#G5KynDY>fjFkG(H zQ?zfD(DiX%S|qokfMW)qkBSq8%%f+Sqj1^RJt9Fa=&Mlo_O{st@0w8cZbKAFc8 zr2VuZOs3S-mlXphZUkq7o+s(O$SGzY(a@6(iAdb*55IAfPyw&0)q#>stdx_fL8ywI z=PYAAjEu(k-(aHk)@*6OPm9OX33P}Mc)Q2epGKi5(68|ja+8nTJVz)+h5cKm@%!M^ za*5&@I5zEQWbUk4;YK%ioQUMOHMZ9 zT68;bm+VzANw1!GLM+_y=B5EtN|X`3p)i@AX6|~Pb4;{vC&AhB?MBWsCI}o2PglE> zDi>d7=Ebl-h+QVWVIDq_E4{`1vc#uV2TVzisEgt;twwE$NXqVEhtUo z(&GJ9AU|sUXrA33ke51qwRGy1kG*OkJ@`>K+3-Fo)_0fFF5K-@6rP9t^(-lT{c~FE zWzr&|S0>!beAQ8WWq8bP`kw>VmKzisgs7_Q0;*5z~tas!3%will1pO@85+ zah-*uU8Jgls*YslYQxYIN7~e4i73t_4%$WK|*vvs@x+9n)Qv&|NVTXmIeY z)`P1CQg%_g__pKxmYD`c{Rx8x1Nf75uBODr_?S)991S&2Eaw{Sa?WFuwf7&!<>4P4 z5l%wp39pMwhsV|E+8BHZAz2~BX4>Eqg zH;I#ob7p1Zh+g8!eSa|2l-dPo?-HBomV_&fnm_g9KEKq3{i4Z9Y|mK74%GSyvljO0 z6+o+CpmmyK!vGDM09F^a(C8jwFlk3msV%KphN_oa^Y!H@ev|LvI7WE>d@Vku>^|R} zkhas2%o>Y7nriU) z>>VwdsAZYctT$c3v>;q%vd+nnbPkzB-c(j1{$63~YDsMZw2aV&F-wWFqL1t9lqZWk zuB^^XkvjLUzgYElaYRx_3C6iaTQ(a>XX~MFZ|&;PDl9&yt7(68Ulyi##yQkm`D^e3=9|3ztaBdpHQ)v*V3H+}E#m zFnW)e$Q9Q!XcT|g8ff2%;5uj~1kfPH|JF#z@In0%cbLn5bkCBq(-EUT(re$Kvnp& z_Ge6PxjsD)gVEKmA1GVcS={Ekfx?+M6zp2!Q!$K?!e-WqjT*vg&mPgacDejl7}^PO z6%JxGs~zDB`A1`lK@ZsL))Hb-sHObHME7;t6Z&(4X7XEJ$AsCyOK@VK zTT4z{G6xwms-u+aNFdfi{oy3Qkc=ycT`WLh<;X0^FehEjEZ}Av-q|9C(u=6{A)XrD z#zT>dEMLc4L`IePJ{JotU&BNBXJlT52Ve>@xx5wb^%IHY!VIf#cYs}pnlGbd+r-5o zKmmur_>+=AEB_3H!t%CWVaore1qPljFy6=faYp zfJ}@{F6*x2vq;LD6HB$FU;!OG6MYJZv{ek#(B7#*n35%Bb%=>lTVjwp#Y#(J1pW295OjDGX}2L~R6;+-{f#y3 z37f=z?UF+N&`c2J9BcNspR@&zZqoTn*6ixg%}<+hXx?9ZHY_me2j?~)?h;EK6*=!q z<}UTjD8c`5IR}40rwSE$sD)CT9fdN6S=&06ASM*Qn#hkSzMvLyh>P9c0R~< zs+UXhqZYkml1^gwzNcsW4)HJP?D^6OLwRC>HtH;Q6L`C|yUrtHZeJt_oCW&Y-`U+-eSjrw*F5bW; z@O$rF4Hy`u-1YR`y*Rsd^p>${O6~6A<|^sUuZHYeLwRf656sfp1!5!^?^N#qJH;JO z8|laHoEQ+s64F?{2?Tvn=}ibSGwc9*Y82bRLHrO62;bf?-a`Y)Of67~%6Mj;7Y?ZX z-B@e>$j0E1Q;ZzxzfX+BiOgIH6~iR3X&=QQ#oQv16NDfcEg0B4G0?h!FU%rkYKGy_JJpxJM8h!n4xs zbLUrhPtg%RB1BT$1MHWptYVcO@k)ogUkB0Jh;Y^;ZsEAZGev?s<^)o~45C0?-wwiU zD4;8mPyhPuWf7t~R?p!2(mS;G+`Y5c>V-9Md-96m8Pzwn_iD!t^WBxw4J-LivK{NQ z%)4pews;%X^8-Y8OoCPU2#fLo<(Q6ao79U*2>IM=kZ(J+;xXJMwdW#}ba27kqWF7O zxqm`&u)js`@1A;~a*7NLKZ$4AFctKB85$}r5x$+LsKh8#pu6>rQU5u?#*cKmsf*%O<9(O6fi4_0a@rgnWf9WYfK>{C3!#iA8;Uc<65m% zn-^nPs#_5j zkTdi+Ae?|;R(ilysE`?Y@86-)O&R(N+)4;WwQaxu%Ut3FrYL|FNa-iVrug6B4IxJPPKqlp+JP3beJ z@bUCqX%E)CO-6s>xT1JuX?7l%t&gD}ix#KAsAbq2Nd(M0(mB+9XpMWgAf>$G?3UH!ao(r*yZcLamd7P{ssPJ#Q*TFO{8$nE?Sk-%B*r($jC=;6 z4nnPkV%()a0S)cvSC5)b?J;KuAr%5D;RjBrLOc>c+@|d>9lw$AzgR^iJ~kIOnyxit zNQF+n;CSSIgnu(YYKrUZ(G`Yi{MElAbzxF8PlYNoK~}SuxJ-Qb%oj(Sr&+uFB@9r0 z#Cr@8$ySQ{4Kkh;i?bRlp2)IUpj7=EFu!K?aRw}N+7zb;x%#n21pVqrjPlsxSH0zj z=4@5-&?4D*Ui9RKy5i?c)|99V%R#y-JGXMQsdcUo#L8HU3bAWqPXp*3pV34QN!@Lt zFF=LIZ$DlV)J;o4ngsw=3UVR`B1p=QjO9Tl5kF!yv^-o+08$A7o9_ji@;48;{DXA zTby4JOH-=7G+G@_QzEGv#ZE8gt&{RGOnpU``tjivP>+>42Og8XYBm7*f*|r_$1Y#n z^2z^ABXN8I8%c(y#og8_kh9P?VrAffgWZZEy4YtjUT2XID5JL6YrGKruF1Y)I)Q9Bv7niTYC1t}9(sBs9)MJPM`qX} z7h-DG95xPRJRU_w-4;h1YPd%vZ5`^kZ_plCJD?5L zhEzr%-!svNBwg8@>C`Y&0&QKI6L0jZiTF!H{IiDSMJ~eNXY%V1?L)NA**Zkpg6Jnx zIGB}9+by`L&R{;GM41zAGA>y7-lAWPEj^?kz{9q<*(@-y>OFTx0K($XJw3?0nY zLx4qJVSUPro753!eUc}J`e~+6y(K}Uz-`UDiJL=pt-8>+_wo^@C?$CG^vTI?$hlSw z6gZAw#g|}n>Rn_YkmlN-M^fTOfa)e>*9!UC*C{U7NL34G5gY*ba3a!N$iEfZ>_N7+ z4LRe;O?}D+YxNLpT{NRd&Kjt%_sI4JX~7ARz0#eA1jP_~d4yl(&?a;2_y}S)_gKB7 ztr^{)hojaC5z$Y(&sDAE+J-~^#VqfmreUjkpk+QDx8jxJNyq^wY2r#QSjtTRw%yu5m`r4j0&5Xi zAMNqfK{=F+e!}x-@)O0qvRolHPhi9wwRFI-K4k~KMPl^IeL$xN=99q}grL>mtB(O7r$4(nQzY&JJrIj}4_4AtA4&NH6SUu6YvHdvze148jegXEMLIZ!S zvnH>vQSL2k1ijqh9`;=BW9``Y{B>2i`O(RH7_?fRLh87{-6NmR;3e=AEj7`t#v zDjgQnW7DZ12sR~YD(Xww{!x&H`Fo~a<>yLfgH;I~e#ph8Pcz#ss;aY$*B~}}G22v& zYZp^z*W6oYps|Vfp4JuJ>4{eS=#vzIK=1j97+4THgXjx0zr&O?PbV+hE!_W7j)N2R zE2V?Rj;vh4MyWfagUf< zUGbV~Z@fgkF=`Fq6~&8jhwnJ82woGtvE}|7K=LUVe-&qZp=Y)-0+|w`e0Ig&o04M_ zCp(K;sj$4Dp}QtdR!(L}I$Y9?iP7IE8++2t=TY`80ZhLoT6DsilwP#0>s zT#d3d+@!r~bDrJ!mLeZaI#&@V4(q5{QyvUns52)AO7ArIT+z>`LDWNn9*C7J1qsJe zZodOvC@7CS^8`fvjYBgDBMRe$JmhXSP6{BdeLP4Xz1h#lz4FP==@TA~IvL3H0q4C> z{o1hXX_tcy^r;XH8dh77PP`X9$E#^~4IlWiPv1G0aeZc<7yJNO(cL^-VroMpeG06|zs}ehO*i(~M{=f#@&ROp zV8{L77y2tBB|V4MoZ5q?J<-;r8)NYPTr1SAu%{>yc;TJ|g{{f4JCNebwTlVt@LKM) zl29TcEqB}#+tcx^MopatN%_p%1!n&0< z93yOiKW=4U=s~1!+Znuj+Ap4jn=^6Dq7gg(=WEiWz)Mt`df zPi_wxVOylZ&)gsm@K6-cXX6|@@VkTENis+x2aepnQq7=C+erqTMKmF+fsgRvADuK& z0n=obyAtDhPfd2k6MTo1ck`@)HSjql+Bn=wkkc8-If=|ZTOA$(TODD2Uy3vx+ORbX zeH8|$eCT4ZJ-=som4&35QAxTX9u3av?YUt>Y6}gRkI3qc^f9?`P3w{L;kka?a6wD1 zj@lE$k5yc+V!BeUUG3xC>58p_aluqgGZTwgk*AbENHh(_#*Icz2Czb>Zm64>aYo?>)g@HHL z-l++Ea=5<(etAV;XdPhRC5nLJO;PA0GflcK$3XNBNkx6QZo{DVHh_TDQ=F`+H653w z>CfW8g0$|T6_#uH!MH*)6R#8T+XLfv-*F{Z$N#Ji8s1Q?U)vQfrnDxQ&=p5=l|{ba zR`^dlMzt|pe#BN(;P*PAq@|zL6>?+vZxEz?>os}vHQ4R5hATox-x>W%b?DQID?rq( zhwXy*IejzsN5AaQDyVcVqz08KeDM@(x~bPEE4#2JK93*PIJ}ZA!4dL+Rs**m#6>f= zpV+gKWDC5`4%+Dz_)w9al;1W8=y7aOw_G5%yUeQ>9yiQ|3&-b={vk(7Iuz)LUU@zHWBi;3;JgD#K5tjX+O#=+W?eTlh z(G~2rp?1XxJ^E@b2O4f;4Y(=CSD4VQh5H*<3ORl|aWcAl!=BIKVE1M}Dl9ZbQkQb3S(}je9-|Nq*#({Q5G1dER!PJ=?{DSO419nTe-us{NB9 zfYYwT+>xnpa?Su2N#2um0%EBQJV|Zui8DV5Lin3M@&v>}`Pa)?I-Y~2&NKj{vmr&1 zM}z8u-0CuF*=;v3jkEv``_QzuQ~@?ufW{lO>6&Aq?^pp=PngCVy6M^^E%sJ@L{~({ z8;<41Bx+tyY_2Yw+6&EA|Eibf!Y68eJLK|0X<=Ym9*J+*{R7rL#0NaLu14Xl z%l~S%XFH6*w?_TL61T43y$c1d-d}IA!_!^c%Pmx{Ug}+*{<3D zqugulfk=O3~E#*;>_7?|=*Js#*5!{c&>&rs3e_TZ2_)D^IMB`OxJG-(b|b!}S}7-WaSs;0Dfn1l9x5 zX6)%2S1;sHQ!2W|T&{U6HE}Y|2CjA;)4YXc#MUZq6IJvYwGjmh&IJn;^~;uh3uf15 z(^kIIt)E!@Nm2EhuvZPHOLB=z^?Gj;nPo^P*+>RhjPAt`qDLwN4&U%vX>6QY&kuwH z)cdZqG2TX_UCiuiw7Y>7`qeFEcd`5JOnv?Hp%P~`FYGOtkn5$m>3IW~>0jU- zG}ti;_b?rF0*CDWZUKqUTlTn$-b7b0%R3*@-g>PlDvq#M!3=J8W&0ZTcvqkZH`eYT zi#`Hzs4$nFuXYV5brd{^F)A zPpv2u>C!H=-*u-8fBLvml&;`v)Ma@fbDFa}aiWq*dm!a{@SP72(WSc$qj89}eTn;6 z^5JUp;TrSd>htsWq*}5?Z2y3HNB^;zH&eTol)^35r)o@TnNJw@>EOJS^(31uA7ovM z7S7{}5JuSZp*hzWeylP}AGpvpeRreukX-UYGoC3gPqvMJ z=$9JzT-tUPc*`tEG#Z-+I<1CSY7k&#YR!SmHx1!5u_SRG(uEUC=L9mLL^Gj8FtH>a zTkt1WDkMM%Z7h6IPYV-T5_)z|st6}nOU#Rt3y~}u(!_Sa2@H%)bck~x%>_o=N!w%e zg&JF?UWv+oM~&J!r}yp7m4k-#ubodx&2H|vXgoAA8;RDhmTZqtu}?h|T`L&Kur;Pj z(wmQtW6rcKV$(Kki^pasI}nwZo5Z&VrWP747Y*mZ2JvR;f`jz02k#P3fX3ID0Px(}-$4lhE$0SG>@ zM@|?dCzg^I2O%d0CnpXjCl)|XFd-+Vk{6H2`&AQ^?2Upw8mS;JxudQdAzB8IJ*Mh& z@~`bh4S{Q>x2_E~2&4gESsSR^!S-Wnp;KBLkkd}eh^`ZLz)B=OC`Jrwc{%b6DcbK)O`v&^P4&>IZV6t1{!J3hQX!~Hhcc7ah!B0u% zQ--`sZ(tpv2Np zLCAwsjgk3=_|juSxoM%CoLKHoAP-N1r~@nm#%{2ZTPXw9ZUE}tIKfDbu&-@^qc4i$ zrzP{oa^7wi>Njhnd25XrksGM?XpJ-anGCBP+iJ(A@ttep%!l156ENtP$J+~x7yKAP^l zqaIvUjcl*Sce~;HT?v2M3Vhm%WOqWkJnAm2YA&qWlr=n*HLNR`x#7oN31xTUS=1r9 zJOVGQLMoV@e@Qt%Hlkv0f90jT5F{>mnUk0eAh^wSCAuJLTRmhCjg-{P`QmC?&s8=!33@enV&O*2^F+@*03??i$aSXkoq1xH_C?V9^#pmmF{*~B z$Q5b?S&o)(zVw0aAV+(%ju$sY86>it+N*`aH*4>wOj*#n8{^n2a=z2+oa0#W^z?NF8@KJAWE#Wlz&o+@Vv~RZgkRon;+1axQ>qYEA}l z^@MQEgm8`gBUqY99Y714%&NECv2k!TJTXPUv+SWETRBuaVQ<*}w1IbbGX`mqQE#)R z8esKZSG44(RLKVV+qJa!XIQGi`x|N!uaY8plE++>!3#U?PbiWL0lsBmA2K*l<0tAF zHhX?~&0o+sFM2bPUvR7Mc<2!?pm7gMC=j8P*eT>Nl>^@8gn5D%z!k~NWeVQ*jf598 zlq(eLYgMUpy~eWDNh8=2p?m7F>U12~o@_H~i1{FV`e9A@4#1z?aeBryx!i$QW!X(W zr8f#6maEV$V?+Av$>6U0Pwtl>7v(h;&8>P`u7)&Rr;6sKQEPyzn@3}hit@sC%?Cyk zo;!qSB&hAbTB{UV&Gkwx7y6|%8)LFHCRok&OqQ$Z>nj=vD>+1g*Yb0_^dz7$@@oS5 zbG>z-ZdEd&O^&`X8d!o4e)ve>Ax*b#3Q1wfW6>89R!`R&OMka_^Dj9rthwA|ak$(p zw=cX_JXR9N^MqWty;eOMwIIc^kEc^J+xxj(IprP-z-zk=&^s{DwyFLb{m%3d#cmS5Qn=uMZd%odMVXIb>z76y9YHh(O3 zEIN(Xv^RTas!i2pYM*caO?JA_Tz+-aAF){Cn_&cMjFAMYj)Jgn7V?=tz@!_|)&d(u zT=;fXa8YI!5a6KrkEy~Y|6$l;IiGGu?hy4%NBBgc9- z(}xdwpJ+PCQzy!&oRS#jI=~iVn7YJQu_`f3pM|9q!}||79XVlYL8aEpv`JSr%CxD= zWXajLuVJ@&9bLaWDz8Ehb=7oJ4!0GzW}L2HV{Su&?r?QaU)a2hsh@cCzTH85d&xOp z0{+@W!a~lYf6{0SBuh3f4sM`YVNs1mq#3h+~InaLU)sMVim>4 zZXwHwOkV2Ti;tNWPwU^YUD~Pn5Nht<TUrZkrY0pntSg;&wOgX^nVWE-(Ouk zBh~oSbV;Q4!zou*Z=)<;8_O=wGC7=5m}+u7rb1J1TTkYy+<-sirFx3G ztxWcs4S7m{yJ9+YqIwFxElz%;yqCT#(|j(^zSyWDAV0JDF8z-UViRU(nP*yO>q`xG zi&vE!PiF{U|H7IY6cvUT69fV(_yPPsfaU!=FO-s%hpDxl+kXO6s=cTosUd%c*x*Zp zEATH+E*1Y+_!Y4j0ZaO09zwpi)j3~?vFC(d$c(hi=CbSR&GyNsPEg0(OE#A8DfaBt zCsBeieS+Wd6_oC7>(A4l?LSvtUUXmYZ^zp}p4VbP(efZGVdb2!iXP^`$_5#52n_-V zJ-}q#qSUUzoS}^9gxVH{(a3Kjwekb6n3irnW;KxI! zb+FYM?+ipzl<(vTmL<-Wl?WmI|2*+ zU7M1?&OBhEf+;N*E%6%0UNR%8q%9R8DY#(5+JaUwA(7t7=Cz8CsuEHZ99gwm4oD`qMg`#mZyg9T0KhNIU9J2Pn{B3laB2mxYeTvEwuLhruM z9veaW;QJ%kzS$rKLs8h7u=&b@$)e2Ac0e2%npB+>x!~SRLXK>BiL!O8NNPzVMr`zC zB;(j0GYJTuYMFsz42j*^!kNv4j2uS6RU5rDO%ljjPXZrDOW};AV&c^z&=wrIiV|)T z5@Vr~uyZAqNo1PP`5Wxek#j`BCV~oyh^ev5^>%1G?fFis-k7-L-5L^9}pHiz95hT&mobIbDK2bs>at5cnI=A$oMtDEoAO0oBTIW?K{2y~lo?vxtyM2z8M#eT&8 z9juXq2^%dkM#pMzKUozSKLuh+C$brn4CCx^QalSYmxd3U2U|O95P{4G9E|z7y535w zze!#4zQ-&dB^7t|K@BcAL|X!p+^fW&%nefLBnXwaSAw{WtK`TaZ{X8maD5z>XsIJ+12jxIx+V<8m)s& z>1hmbjRh?7Iu%?AdmA%zGrO}d@nK>_z{kSFM@Nau4TgwqT&m{N64X4n12267iNvuB zoYs)UpV~vPFqwuLX|tXTEf1p2nxKfJ0%X$TL+;}xvO9%&PS{DgwClW32|LOprsKwW z!)zb%*G3frXRpPr&1a^~D*9rY|D0@SG+qL#DmGeTZC~l^iOz**2PmO@z7slCP&8L1 z8+7XXR z{tm)YmJeheC-bE0Pa6}UJ6&I`B0=^G!gEf`} z$2e~n6>}5SbF_~)G`J)ym{b^%WTAhlGWQeH!ZoPK5CWt139!eE*OTXyg?^(CHF?3l zT-)drldi`ad)P8_(e;Zrbo3}|)D(b%b4DJs3IVTf)$H%lXzyg6-48R)pSjMz@S{!x zG`M!S(;dnBSg@7>Z)-4>A?k~$p+uJ zH1I4YQ~eUc+V#59^^O?*Y~X_IG^ni;3|+B=cTx3kJ!o6VVH*pq#qvR8`B#ISd|qcW z*ku5bJnU)kye=)gOTI4q`Pg8-=+ZcqThdW-5nJTLVO^Mfn>e!01)Mecp`idcwF#A& zcsrw1K<2}O?X>toUlT-vO2f)BJ1KRLgp|^d#`zOA3cUPc#QVHL=y$9TAe}hQ<-!FvkGZ_(O0U8NeQ92s~R})u69p_2Auc&*U-e&SX%R!QWiB2E^+VhfSWfH5ixxtom^M;^YvZq-usr4CxeovTfh|B5%$he zQL}@chmkIvDUEzFl!zw4rVI!Rzk!Tui|4HI3T81he^y?>M{Oi0$y#TCr zge4;DC3Y67=F*u>j%j_w5jY=Kwr3;vI4R=+h95zosJ526}k7$my!3I^6+x6DT z{^_qqLAXQTjQi>Ji>CxcaSn1s4&A!R0q29ojOVbwYqYeEYKj216$6=+dmhd;!iT*Z zj&<{?IKBpx+G4u|p$lmv!eZTGQ8RUU(gayp%u883$tjGMJe}mqYJ-f*ZaYjlTur_C zR}=XTT6+kaaLBV?AI!uW zcd*uz@f%*vM^pIgkCz%`R-qghxBl-@WS6Dnglw8eEG0Se0_HhPrOCHSdyf1pOp3ya z*C;QdEF4qpEFqH^=8PJQTB7-X$jAbB5w#ShD0{>K1_Af9QznSqBq6H&$W1HM0j-JP zRc$0mR(UTG3lP%WmG4f_VCn1%4^d1?g0ioH%(wfDuC`192nMU{+xPat&?#26~pG#5@F+Lvs+X0qL-EmUi%dRC58Gls9tX>G1J! zjC2LiENFI;@dOhR4Mji@I`g3a&MdYR6}4nYYlsRS6&%MS!Rv8jXa?y?nL^fTV%mE& z524lhT@cM-JEZhHs-ypJj3pChhO#JZy?p2(8Bq?)XC15Z8ha#m5<8&z625V*9$L%K zUz2-C^+_xt7LskmO@s@8^V~wguq5V*UFLN2Yg`#kIyoIi#uLgDsx{?t{kbw9#sZCG zs(wa2Txss{Ub10Y9X9h0C~|R_BU7aC0z95E?-o4PVa)>%)GtmbVH~0j0o6Yo2BJgi z!}Q*NJ<$L1Y_+s4C?ps3oD1qWEzUvTKFR(b;UHG{gmSN-MRteqp$e;<=`@k z>l3=eKg`7)gn5C@!7aS6!j`wauP@`p)UNVpuujWjoh~;d?*y1_3r+WU{cVW%@t%NM zACKAWEt)h`L+9ypO5L^ZJi|gP@Cm*pHC3#@$#0vwHtvCX2v+0ck??QzxIkduZcHD) z`vN(8B;DggfY99GQq)s@=zKIMf#!&}(-GopJgNJV(e_ zRWEl`<=yv|19YKSX7X~IIX(D2)XxpyU;Mn)*`CU76-^{gG*o=!H!vEFA&EHKBdEQZ zNiM-qF?7nTpcCLb7h;IZxcfthBR(M35G|P|;!?u;!uv~l{;oM`x@nzhIfVSRtz%-U z#7{3!;80gcga{6x{%O)oCNguFF>Br;O@i#9D@j39RqITm&8SZTC$6m*&4co5Q5{_# zQuPTDAU7C9NYV4WV|itv zkBhuz+!${985fcIl=?41g79G#R{qX`jYcRGK@0YiQCfaAeXpsnABeLiC)V1F z06pRsJMAvMFt#-NPEV?L@doQ5g6E&UoJ`TNvGME^f62c3yrVXKe(t;O{>8txS$UPm zYcZmT&E=fn2D*Y=#Gi9?ii?ObQR6>KDX&5KIx!Po2g@AT?DJbAIK_22z`SfF@k&j& zYK}jqcbmQ<-@nMy!S>IZRNHnyLC~7?(;Mhsw_H+`etR>xJJ)ZR^?zy9>>cgwO&pyqOq`^sDMzKHq-k%Y>u9E`rN>9Em;VR3{`KD)hWY*J ze+7P)_;0&$A4M6tZ@&9%kvx!q9kRV)5u>%phaHKiR8gcvQd~(-z4c;LsZ?veh3=z& z=#v>`DeyQlXTuwy;?vd~ii!uz!@PccIO(|A^w3xm?w$GONprols?Tw3tA()(n92 z82fB#Hrx%(*=Q#slHFWu%Y3-qLU^tqNE`24DHUM09e*ZSB1FyHVA2=^0ZILRdi{+_ z$Cw>FNrhz zNak%CMB1(O;_GRt;*+j^Bs4P2y_=V20GaGQMr7AX(}JQU^y$m}kTL-QgNdUl7T1T1 zNK2-tGVBDvh=Qw&72VP)24{e+@)yxAG9#`Ak*eNy1izqK6G4Xt>Vz92baStTKDzTg z{|l;I#wc6L^qW3b^S{x@{(EozvwZunz2#)$=xSkPVqj!s=VI&pKQ6QWT^0WStjfjN z!uo%ukLmx1K0y-$M-#_?@gMvjF!ki<{{yDJrU~u^hW1xDa0eP09BogK4sl<7eF!X} zd2dnM9SDI$bfeXU_l^%Vmu-6a16V)AHjG|4lwd1;Oj6S%0zH8PTFTW9W-d{CAt1kd zK@lVM)LH0o6<0xZHWPf>G%`lqrkxen~S?hkO^C=KF3RzRUmj z#QJB({|{aDuji{|VPHp&F8-qlN)+GD3ZM$#VcK2=DwsG6GZQHhO+qP}n zz5U*s*qEKzH!-^r6;buKs!rs0zC2%M67n|fQ#kzvIh^lrV~eo6HGo{jxpjQv(1lrF7- zYq(yfxL_jxB_gEh(i^ElEaGn0NID&erWH4>CeO<_ID?QJh1_-%C$YgHUyxbk6qTNiux7MkrdBvUQB1x8gc872}WW7!4vJUl+A#;(cYWB#=NcSX8?qZj4S zLO{~`-7B(A*1B{{`oqA**9et^7m=Vq`DYz_V~EL~u3;~r6hZox*0iZpV*2Kg!-3s7 zKnh_M$bJm%4j(F|lNUF(CDd9kYk^KD($}3dF6kNCIpc=FN!YPHYjsP?NDv_&-u>l_ zC=}a)YP-OVCZ~t$N#>)<6P}mZ=?vRm51Iqf%oLZ(YHw>cFinNLf`6~3nM>-CPk?7gMM zZi>A{en!c*$kT~$^Ykhb_<1%fQn_2#O}TL^W>IQ>?35lL!vK<6fzbrN`zH#&l(lhkgPX#1gN9!aEetK_HAp7h2b z|5BPfr6Y;{3F9E;x#SO(q_9Nk$XjYY_%{!aHNB3HC9MUdIc+alio|Ld$IqNLp?M+6 zO@JkR4qrpkG=W4QP0BR3GRT7QkYm+q3^v#KsKBh@cdQMO`r=RSZ0l0Yxl}8k6_ZhM z1EyU(`7cw(Laj7Kn0Z&zqr!=UM2lot1-)W&Ekq`x<_r2;>?~GdBJ0jlkzg0dFA zzpaC*bCpmhu`EY9vl>$gHC0W^37vgd`wxs;Pm-Z!1u0dLRb2UOUKjW)3~%x(r8>r8X#ac1aEB z#x!HFE>{f3`tL%VfK!m+%zAK*%%gF~TW9~!{7#10NEkk_709AHBzIj)5V(sVpB9hT zT@0RpGP}1g;-aNZu~TiLqpZGv?F{NL8I!nELdx#_>&jzdX7#XG&3elOn|jA=q~Xz} zK?s8x>Th)V`WL|KqL@Eq`y2y;n_BSfQ&7^P=%`B6rTc!>W){OrJfMH2IcWg5p7}-J z4Fg)?a-kMZBdD5xK0AH9K5w=)9F4Y#=NIip^UH~IL_iU7ndx!ha>5sS+)R^VBQfUq zAMr&(8A@BraV3qNKJ#&xA~7<}Tu2R`yu(PY&5Ad8%#8Y_cn(_Rs|fkCs+#No-9tC) z&gR;p)%CRl4V~*sbIYxcS&i+5wkq5EqNO!q>&)h^Rh9j}VE25K&);v4+D~@#FT)9C zGC&>YF~|u@hJ&LO3!`T4ib6KIN*RlNEYGan#wlYssa$*Y8_-`g^{i?Uw02FaC(3ni;=jGpuPc0HGlwESFA47LL1{Zp73 zS%81bP1*}}iZc!Agp>(qiSA7c+)v+ms`Hnd=asfP2@5^3k3z?6<3ftG4y76hbvkYy z4M{OW%Y>2)x9}(hAVml9R#19j76{l|;+v6^o!*3MD(9^0SHW#rI1*`#SB(Hpo!7sx zm!mOORBUfZN@$$5j!!JS$L`$OZ≺Wwz-=>MpErVx2etYW6p)XCF;X0@v1el&G`p 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 + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + shade-for-japicmp + package + + shade + + + true + with-common + + + com.skyflow:common + + + + + + + + com.github.siom79.japicmp + japicmp-maven-plugin + 0.26.0 + + + + + ${project.basedir}/api-report/skyflow-java.baseline.jar + + + + + ${project.build.directory}/${project.build.finalName}-with-common.jar + + + + protected + true + false + true + true + + com.skyflow.generated.* + com.skyflow.utils.* + + false + false + + + + + default-cli + verify + + cmp + + + + From 5c519c16ac996a4a32bb0d6d34bf2d358a1664dd Mon Sep 17 00:00:00 2001 From: skyflow-bharti Date: Mon, 27 Jul 2026 11:47:10 +0530 Subject: [PATCH 28/28] SK-2967 added query and get methods --- .../java/com/skyflow/errors/ErrorMessage.java | 9 + .../main/java/com/skyflow/logs/ErrorLogs.java | 9 + .../skyflow/vault/data/BaseGetRequest.java | 47 ++ .../skyflow/vault/data/BaseGetResponse.java | 34 + .../skyflow/vault/data/BaseQueryRequest.java | 25 + .../skyflow/vault/data/BaseQueryResponse.java | 37 ++ .../java/com/skyflow/BaseSkyflowTests.java | 82 ++- .../com/skyflow/BaseVaultClientTests.java | 138 ++++ .../serviceaccount/util/BearerTokenTests.java | 57 ++ .../util/SignedDataTokensTests.java | 137 +++- .../com/skyflow/utils/BaseUtilsTests.java | 106 +++ .../utils/logger/LogUtilLevelTests.java | 64 ++ .../vault/data/BaseDetokenizeDataTests.java | 28 + .../BaseDetokenizeRecordResponseTests.java | 39 ++ .../data/BaseDetokenizeRequestTests.java | 24 + .../vault/data/BaseInsertRequestTests.java | 41 ++ .../vault/data/BaseInsertResponseTests.java | 69 ++ .../vault/data/RequestContextTests.java | 68 ++ .../vault/data/RequestInterceptorTests.java | 28 + .../main/java/com/skyflow/VaultClient.java | 5 + .../java/com/skyflow/enums/InterfaceName.java | 4 +- .../main/java/com/skyflow/utils/Utils.java | 119 ++++ .../utils/validations/Validations.java | 161 +++++ .../vault/controller/VaultController.java | 66 ++ .../skyflow/vault/data/ColumnRedaction.java | 40 ++ .../com/skyflow/vault/data/GetOptions.java | 30 + .../skyflow/vault/data/GetRecordRequest.java | 71 ++ .../com/skyflow/vault/data/GetRequest.java | 102 +++ .../com/skyflow/vault/data/GetResponse.java | 10 + .../com/skyflow/vault/data/QueryOptions.java | 30 + .../com/skyflow/vault/data/QueryRequest.java | 26 + .../com/skyflow/vault/data/QueryResponse.java | 10 + .../java/com/skyflow/utils/UtilsTests.java | 414 ++++++++++++ .../utils/validations/ValidationsTests.java | 518 +++++++++++++++ .../controller/VaultControllerTests.java | 628 ++++++++++++++++++ .../skyflow/vault/data/BulkResponseTests.java | 225 +++++++ .../com/skyflow/vault/data/OptionsTests.java | 71 ++ .../vault/data/RecordAndRedactionTests.java | 161 +++++ .../data/RequestResponseWrapperTests.java | 303 +++++++++ .../vault/data/ResponseComponentTests.java | 276 ++++++++ .../com/skyflow/vault/data/GetRequest.java | 37 +- .../com/skyflow/vault/data/GetResponse.java | 37 +- .../com/skyflow/vault/data/QueryRequest.java | 17 +- .../com/skyflow/vault/data/QueryResponse.java | 32 +- 44 files changed, 4333 insertions(+), 102 deletions(-) create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseGetRequest.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseGetResponse.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseQueryRequest.java create mode 100644 common/src/main/java/com/skyflow/vault/data/BaseQueryResponse.java create mode 100644 common/src/test/java/com/skyflow/vault/data/BaseDetokenizeDataTests.java create mode 100644 common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRecordResponseTests.java create mode 100644 common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRequestTests.java create mode 100644 common/src/test/java/com/skyflow/vault/data/BaseInsertRequestTests.java create mode 100644 common/src/test/java/com/skyflow/vault/data/BaseInsertResponseTests.java create mode 100644 common/src/test/java/com/skyflow/vault/data/RequestContextTests.java create mode 100644 common/src/test/java/com/skyflow/vault/data/RequestInterceptorTests.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/ColumnRedaction.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/GetOptions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/GetRecordRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/GetRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/GetResponse.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/QueryOptions.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/QueryRequest.java create mode 100644 flowvault/src/main/java/com/skyflow/vault/data/QueryResponse.java create mode 100644 flowvault/src/test/java/com/skyflow/vault/data/BulkResponseTests.java create mode 100644 flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java create mode 100644 flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java create mode 100644 flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java create mode 100644 flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java diff --git a/common/src/main/java/com/skyflow/errors/ErrorMessage.java b/common/src/main/java/com/skyflow/errors/ErrorMessage.java index 1e4d9178..d835cb98 100644 --- a/common/src/main/java/com/skyflow/errors/ErrorMessage.java +++ b/common/src/main/java/com/skyflow/errors/ErrorMessage.java @@ -119,6 +119,15 @@ public enum ErrorMessage { ColumnValuesKeyErrorGet("%s0 Validation error. 'columnValues' aren't specified whereas 'columnName' is specified. Either add 'columnValues' or remove 'columnName'."), EmptyColumnValues("%s0 Validation error. 'columnValues' can't be empty. Specify at least one column value"), EmptyValueInColumnValues("%s0 Validation error. Invalid value in column values. Specify a valid column value."), + IdsOrUniqueValuesKeyError("%s0 Validation error. 'ids' or 'uniqueValues' key is missing from the payload. Specify ids or uniqueValues in payload."), + BothIdsAndUniqueValuesSpecified("%s0 Validation error. Both Skyflow IDs and unique values can't be specified. Either specify Skyflow IDs or unique values."), + EmptyUniqueValues("%s0 Validation error. 'uniqueValues' can't be empty. Specify at least one unique value."), + EmptyUniqueValueInUniqueValues("%s0 Validation error. Invalid unique value in 'uniqueValues'. Specify a valid unique value."), + NullColumnRedactions("%s0 Validation error. Column redaction object can not be null. Specify a valid column redaction object."), + NullColumnNameInColumnRedaction("%s0 Validation error. Column name can not be null or empty in column redaction. Specify a valid column name."), + NullRedactionInColumnRedaction("%s0 Validation error. Redaction can not be null or empty in column redaction. Specify a valid redaction."), + BothSingleTableFieldsAndRecordsSpecified("%s0 Validation error. Both single-table lookup fields ('table', 'ids', 'fields', 'uniqueValues', 'columnRedactions') and 'records' can't be specified. Either specify single-table fields or 'records'."), + NullGetRecordRequest("%s0 Validation error. Record in 'records' is null. Specify a valid record."), TokenKeyError("%s0 Validation error. 'token' key is missing from the payload. Specify a 'token' key."), PartialSuccess("%s0 Validation error. Check 'SkyflowError.data' for details."), diff --git a/common/src/main/java/com/skyflow/logs/ErrorLogs.java b/common/src/main/java/com/skyflow/logs/ErrorLogs.java index bbb96fce..0156680c 100644 --- a/common/src/main/java/com/skyflow/logs/ErrorLogs.java +++ b/common/src/main/java/com/skyflow/logs/ErrorLogs.java @@ -104,6 +104,15 @@ public enum ErrorLogs { EMPTY_COLUMN_VALUES("Invalid %s1 request. Column values can not be empty."), EMPTY_OR_NULL_COLUMN_VALUE_IN_COLUMN_VALUES("Invalid %s1 request. Column value can not by null or empty in column values at index %s2."), GET_REQUEST_REJECTED("Get request resulted in failure."), + NEITHER_IDS_NOR_UNIQUE_VALUES_PASSED("Invalid %s1 request. Neither ids nor unique values are passed."), + BOTH_IDS_AND_UNIQUE_VALUES_PASSED("Invalid %s1 request. Both ids and unique values are passed."), + EMPTY_UNIQUE_VALUES("Invalid %s1 request. Unique values can not be empty."), + EMPTY_OR_NULL_UNIQUE_VALUE_IN_UNIQUE_VALUES("Invalid %s1 request. Unique value can not be null or empty in unique values at index %s2."), + NULL_COLUMN_REDACTION_OBJECT("Invalid %s1 request. Column redaction object can not be null."), + NULL_COLUMN_NAME_IN_COLUMN_REDACTION("Invalid %s1 request. Column name can not be null or empty in column redaction."), + EMPTY_OR_NULL_REDACTION_IN_COLUMN_REDACTION("Invalid %s1 request. Redaction can not be null or empty in column redaction."), + BOTH_SINGLE_TABLE_FIELDS_AND_RECORDS_PASSED("Invalid %s1 request. Both single-table lookup fields and records are passed."), + NULL_GET_RECORD_REQUEST_OBJECT("Invalid %s1 request. Record in records list can not be null."), DATA_IS_REQUIRED("Invalid %s1 request. Data is required."), EMPTY_DATA("Invalid %s1 request. Data can not be empty."), SKYFLOW_ID_IS_REQUIRED("Invalid %s1 request. Skyflow Id is required."), diff --git a/common/src/main/java/com/skyflow/vault/data/BaseGetRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseGetRequest.java new file mode 100644 index 00000000..de2ecd12 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseGetRequest.java @@ -0,0 +1,47 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; + +public class BaseGetRequest { + private final BaseGetRequestBuilder builder; + + protected BaseGetRequest(BaseGetRequestBuilder builder) { + this.builder = builder; + } + + public String getTable() { + return this.builder.table; + } + + public ArrayList getIds() { + return this.builder.ids; + } + + public ArrayList getFields() { + return this.builder.fields; + } + + static class BaseGetRequestBuilder { + protected String table; + protected ArrayList ids; + protected ArrayList fields; + + protected BaseGetRequestBuilder() { + } + + public BaseGetRequestBuilder table(String table) { + this.table = table; + return this; + } + + public BaseGetRequestBuilder ids(ArrayList ids) { + this.ids = ids; + return this; + } + + public BaseGetRequestBuilder fields(ArrayList fields) { + this.fields = fields; + return this; + } + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseGetResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseGetResponse.java new file mode 100644 index 00000000..34545b7f --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseGetResponse.java @@ -0,0 +1,34 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.HashMap; + +public class BaseGetResponse { + private final ArrayList> data; + private final ArrayList> errors; + + public BaseGetResponse(ArrayList> data, ArrayList> errors) { + this.data = data; + this.errors = errors; + } + + /** + * Returns the list of record maps from the Get response. Each map contains all + * field name/value pairs for the record. + */ + public ArrayList> getData() { + return data; + } + + public ArrayList> getErrors() { + return errors; + } + + @Override + public String toString() { + Gson gson = new Gson().newBuilder().serializeNulls().create(); + return gson.toJson(this); + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseQueryRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseQueryRequest.java new file mode 100644 index 00000000..01ca3d46 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseQueryRequest.java @@ -0,0 +1,25 @@ +package com.skyflow.vault.data; + +public class BaseQueryRequest { + private final BaseQueryRequestBuilder builder; + + protected BaseQueryRequest(BaseQueryRequestBuilder builder) { + this.builder = builder; + } + + public String getQuery() { + return this.builder.query; + } + + static class BaseQueryRequestBuilder { + protected String query; + + protected BaseQueryRequestBuilder() { + } + + public BaseQueryRequestBuilder query(String query) { + this.query = query; + return this; + } + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseQueryResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseQueryResponse.java new file mode 100644 index 00000000..1930d66d --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseQueryResponse.java @@ -0,0 +1,37 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.HashMap; + +public class BaseQueryResponse { + private final ArrayList> fields; + private final ArrayList> errors; + + public BaseQueryResponse(ArrayList> fields) { + this.fields = fields; + this.errors = null; + } + + /** + * Returns the list of record maps from the Query response. Each map contains all + * field name/value pairs for the record. + */ + public ArrayList> getFields() { + return fields; + } + + /** + * Always returns null. The Query API does not support partial-error responses. + */ + public ArrayList> getErrors() { + return errors; + } + + @Override + public String toString() { + Gson gson = new Gson().newBuilder().serializeNulls().create(); + return gson.toJson(this); + } +} diff --git a/common/src/test/java/com/skyflow/BaseSkyflowTests.java b/common/src/test/java/com/skyflow/BaseSkyflowTests.java index 2e18a1ea..cfd65ad5 100644 --- a/common/src/test/java/com/skyflow/BaseSkyflowTests.java +++ b/common/src/test/java/com/skyflow/BaseSkyflowTests.java @@ -260,6 +260,77 @@ public void testMergeVaultConfigWithNullClusterIdFallsBackToPreviousClusterId() Assert.assertEquals(clusterID, result.getClusterId()); } + @Test + public void testVaultReturnsFirstEntryWhenNoVaultIdSpecified() throws SkyflowException { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(config).build(); + + Object vault = client.vault(); + + Assert.assertNotNull(vault); + Assert.assertSame(vault, client.vault(vaultID)); + } + + @Test + public void testVaultByIdReturnsConfigSpecificEntry() throws SkyflowException { + String secondaryId = vaultID + "123"; + BaseVaultConfig primary = newConfig(vaultID, clusterID, Env.SANDBOX); + BaseVaultConfig secondary = newConfig(secondaryId, clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(primary).addVaultConfig(secondary).build(); + + Object primaryVault = client.vault(vaultID); + Object secondaryVault = client.vault(secondaryId); + + Assert.assertNotNull(primaryVault); + Assert.assertNotNull(secondaryVault); + Assert.assertNotSame(primaryVault, secondaryVault); + Assert.assertSame(primaryVault, client.vault(vaultID)); + } + + @Test + public void testGettingExistingVaultConfigReturnsStoredConfig() throws SkyflowException { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder().addVaultConfig(config).build(); + + BaseVaultConfig stored = client.getVaultConfig(vaultID); + + Assert.assertNotNull(stored); + Assert.assertEquals(vaultID, stored.getVaultId()); + Assert.assertEquals(clusterID, stored.getClusterId()); + Assert.assertEquals(Env.SANDBOX, stored.getEnv()); + } + + @Test + public void testInstanceSetLogLevelNullResetsToDefault() throws SkyflowException { + TestSkyflow client = TestSkyflow.builder().setLogLevel(LogLevel.INFO).build(); + Assert.assertEquals(LogLevel.INFO, client.getLogLevel()); + + client.setLogLevel(null); + + Assert.assertEquals(LogLevel.ERROR, client.getLogLevel()); + } + + @Test + public void testUpdateVaultConfigLeavesOldConfigWhenHookThrows() throws SkyflowException { + BaseVaultConfig config = newConfig(vaultID, clusterID, Env.SANDBOX); + TestSkyflow client = TestSkyflow.builder() + .addVaultConfig(config) + .failVaultConfigUpdateFor(vaultID) + .build(); + + BaseVaultConfig update = newConfig(vaultID, newClusterID, Env.PROD); + try { + client.updateVaultConfig(update); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + // expected: onVaultConfigUpdated hook forced a failure + } + + BaseVaultConfig stillOld = client.getVaultConfig(vaultID); + Assert.assertEquals(clusterID, stillOld.getClusterId()); + Assert.assertEquals(Env.SANDBOX, stillOld.getEnv()); + } + private static class TestSkyflow extends BaseSkyflow { private final TestSkyflowClientBuilder builder; @@ -289,6 +360,7 @@ Object vault(String vaultId) throws SkyflowException { private static class TestSkyflowClientBuilder extends BaseSkyflowClientBuilder { private final java.util.LinkedHashMap vaultClientsMap = new java.util.LinkedHashMap<>(); + private String vaultIdToFailUpdate; @Override protected void validateVaultConfig(BaseVaultConfig vaultConfig) throws SkyflowException { @@ -303,10 +375,18 @@ protected void onVaultConfigAdded(BaseVaultConfig vaultConfig) { } @Override - protected void onVaultConfigUpdated(BaseVaultConfig updatedConfig) { + protected void onVaultConfigUpdated(BaseVaultConfig updatedConfig) throws SkyflowException { + if (updatedConfig.getVaultId().equals(this.vaultIdToFailUpdate)) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), "forced update hook failure"); + } this.vaultClientsMap.put(updatedConfig.getVaultId(), new Object()); } + TestSkyflowClientBuilder failVaultConfigUpdateFor(String vaultId) { + this.vaultIdToFailUpdate = vaultId; + return this; + } + @Override protected void onVaultConfigRemoved(String vaultId) { this.vaultClientsMap.remove(vaultId); diff --git a/common/src/test/java/com/skyflow/BaseVaultClientTests.java b/common/src/test/java/com/skyflow/BaseVaultClientTests.java index c8c128f2..ec78c397 100644 --- a/common/src/test/java/com/skyflow/BaseVaultClientTests.java +++ b/common/src/test/java/com/skyflow/BaseVaultClientTests.java @@ -4,7 +4,15 @@ import com.skyflow.config.BaseVaultConfig; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; +import com.skyflow.logs.ErrorLogs; import com.skyflow.utils.BaseConstants; +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -15,6 +23,11 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; public class BaseVaultClientTests { @@ -163,4 +176,129 @@ public void testPrioritiseCredentials_dotenvKeyMissing_throwsSkyflowException() Assert.assertTrue(e.getMessage().contains(ErrorMessage.EmptyCredentials.getMessage())); } } + + /** + * Covers buildSharedHttpClient: the interceptor it installs must inject + * "Authorization: Bearer " using the supplied tokenSupplier. No real network call is + * made; a hand-rolled Interceptor.Chain captures the request that would be sent. + */ + @Test + public void testBuildSharedHttpClient_injectsAuthorizationHeaderFromTokenSupplier() throws IOException { + BaseVaultClient client = newClient(null); + Supplier tokenSupplier = () -> "test-shared-token"; + + OkHttpClient httpClient = client.buildSharedHttpClient(tokenSupplier); + + Assert.assertEquals(1, httpClient.interceptors().size()); + Interceptor interceptor = httpClient.interceptors().get(0); + + Request originalRequest = new Request.Builder().url("https://example.com/").build(); + final Request[] capturedRequest = new Request[1]; + Interceptor.Chain fakeChain = new Interceptor.Chain() { + @Override + public Request request() { + return originalRequest; + } + + @Override + public Response proceed(Request request) { + capturedRequest[0] = request; + return new Response.Builder() + .request(request) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("OK") + .build(); + } + + @Override + public Connection connection() { + return null; + } + + @Override + public Call call() { + throw new UnsupportedOperationException(); + } + + @Override + public int connectTimeoutMillis() { + return 0; + } + + @Override + public Interceptor.Chain withConnectTimeout(int timeout, TimeUnit unit) { + throw new UnsupportedOperationException(); + } + + @Override + public int readTimeoutMillis() { + return 0; + } + + @Override + public Interceptor.Chain withReadTimeout(int timeout, TimeUnit unit) { + throw new UnsupportedOperationException(); + } + + @Override + public int writeTimeoutMillis() { + return 0; + } + + @Override + public Interceptor.Chain withWriteTimeout(int timeout, TimeUnit unit) { + throw new UnsupportedOperationException(); + } + }; + + interceptor.intercept(fakeChain); + + Assert.assertNotNull(capturedRequest[0]); + Assert.assertEquals("Bearer test-shared-token", capturedRequest[0].header("Authorization")); + } + + /** + * Covers wrapApiException: the returned SkyflowException should carry the given status code, + * and its message should reflect the JSON-serialized responseBody (round-tripped through Gson + * exactly as wrapApiException does internally). + */ + @Test + public void testWrapApiException_carriesStatusCodeAndJsonResponseBody() { + Map errorBody = new HashMap<>(); + errorBody.put("message", "something went wrong"); + Map responseBody = new HashMap<>(); + responseBody.put("error", errorBody); + Map> headers = new HashMap<>(); + + SkyflowException exception = BaseVaultClient.wrapApiException( + 400, new RuntimeException("network error"), headers, responseBody, ErrorLogs.INSERT_RECORDS_REJECTED); + + Assert.assertEquals(400, exception.getHttpCode()); + Assert.assertEquals("something went wrong", exception.getMessage()); + } + + /** + * Covers setBearerToken's "token present but expired -> regenerate" branch. A hand-crafted + * always-expired JWT ("x.eyJleHAiOjF9.y", exp=1 => 1970) is seeded directly into the token + * field, bypassing setBearerToken. The very same credentials instance used to seed + * finalCredentials is then reused when calling setBearerToken, so prioritiseCredentials does + * NOT treat this as a credential change (that branch is covered by + * testPrioritiseCredentials_credentialChange_resetsTokenAndApiKey) - isolating the isExpired + * branch specifically. + */ + @Test + public void testSetBearerToken_expiredToken_regeneratesToken() throws SkyflowException { + BaseCredentials creds = new BaseCredentials(); + creds.setToken("x.eyJleHAiOjk5OTk5OTk5OTl9.y"); // far-future exp -> not expired once (re)generated + BaseVaultClient client = newClient(null); + + client.prioritiseCredentials(creds); + client.token = "x.eyJleHAiOjF9.y"; // exp=1 (1970) -> always expired, seeded directly + + client.setBearerToken(creds); + + Assert.assertEquals("x.eyJleHAiOjk5OTk5OTk5OTl9.y", client.token); + Assert.assertNotEquals("x.eyJleHAiOjF9.y", client.token); + } } diff --git a/common/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java b/common/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java index bc8f09b5..fb5a2c32 100644 --- a/common/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java +++ b/common/src/test/java/com/skyflow/serviceaccount/util/BearerTokenTests.java @@ -1,8 +1,11 @@ package com.skyflow.serviceaccount.util; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.auth.rest.core.ApiClientException; import com.skyflow.utils.BaseConstants; import com.skyflow.utils.BaseUtils; import org.junit.Assert; @@ -10,7 +13,11 @@ import org.junit.Test; import java.io.File; +import java.io.IOException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -268,4 +275,54 @@ public void testBearerTokenWithNewFormCredentialKeys() { e.getMessage()); } } + + /** + * Generates a real, valid PKCS#8-encoded RSA private key PEM string, using the same + * header/footer BaseUtils.getPrivateKeyFromPem expects, so tests can exercise JWT + * signing (getSignedToken()) instead of always failing at key parsing. + */ + private static String generateValidPkcs8PrivateKeyPem() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + String base64EncodedKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()); + return BaseConstants.PKCS8_PRIVATE_HEADER + "\n" + base64EncodedKey + "\n" + BaseConstants.PKCS8_PRIVATE_FOOTER; + } + + @Test + public void testGetSignedTokenAndScopeUsingRolesExecuteWithValidKeyRolesAndContext() { + try { + String privateKeyPem = generateValidPkcs8PrivateKeyPem(); + ArrayList testRoles = new ArrayList<>(); + testRoles.add("test_role_one"); + testRoles.add("test_role_two"); + Map ctxMap = new HashMap<>(); + ctxMap.put("role", "admin"); + ctxMap.put("department", "finance"); + + JsonObject credentials = new JsonObject(); + credentials.addProperty("privateKey", privateKeyPem); + credentials.addProperty("clientId", "client_id_value"); + credentials.addProperty("keyId", "key_id_value"); + // Syntactically valid but unreachable, so failure surfaces at the network call, + // proving getSignedToken() (with the ctx claim) and getScopeUsingRoles() (roles != null) + // both executed successfully first. + credentials.addProperty("tokenUri", "https://localhost:1"); + String credentialsString = new Gson().toJson(credentials); + + BearerToken bearerToken = BearerToken.builder() + .setCredentials(credentialsString) + .setCtx(ctxMap) + .setRoles(testRoles) + .build(); + bearerToken.getBearerToken(); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (ApiClientException e) { + // Reaching this network-layer exception (rather than a SkyflowException from key + // parsing) confirms getSignedToken() and getScopeUsingRoles() both ran successfully. + Assert.assertTrue(e.getCause() instanceof IOException); + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN + ": " + e); + } + } } diff --git a/common/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java b/common/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java index 1465c2ca..79542476 100644 --- a/common/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java +++ b/common/src/test/java/com/skyflow/serviceaccount/util/SignedDataTokensTests.java @@ -1,16 +1,25 @@ package com.skyflow.serviceaccount.util; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; +import com.skyflow.utils.BaseConstants; import com.skyflow.utils.BaseUtils; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.io.File; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.KeyPairGenerator; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; +import java.util.List; import java.util.Map; public class SignedDataTokensTests { @@ -128,12 +137,10 @@ public void testEmptyCredentialsString() { Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals( - BaseUtils.parameterizedString(ErrorMessage.InvalidCredentials.getMessage(), invalidJsonFilePath), - e.getMessage() - ); + // InvalidCredentials has no %s1 placeholder, so no extra arg is passed here. + Assert.assertEquals(ErrorMessage.InvalidCredentials.getMessage(), e.getMessage()); } catch (Exception e) { - System.out.println(e); + Assert.fail(INVALID_EXCEPTION_THROWN + ": " + e); } } @@ -145,10 +152,8 @@ public void testInvalidCredentialsString() { Assert.fail(EXCEPTION_NOT_THROWN); } catch (SkyflowException e) { Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals( - BaseUtils.parameterizedString(ErrorMessage.CredentialsStringInvalidJson.getMessage(), invalidJsonFilePath), - e.getMessage() - ); + // CredentialsStringInvalidJson has no %s1 placeholder, so no extra arg is passed here. + Assert.assertEquals(ErrorMessage.CredentialsStringInvalidJson.getMessage(), e.getMessage()); } } @@ -258,4 +263,118 @@ public void testSignedDataTokenResponse() { Assert.fail(INVALID_EXCEPTION_THROWN); } } + + /** + * Generates a real, valid PKCS#8-encoded RSA private key PEM string, using the same + * header/footer BaseUtils.getPrivateKeyFromPem expects, so tests can exercise the actual + * JWT signing path (getSignedToken()) instead of always failing at key parsing. + */ + private static String generateValidPkcs8PrivateKeyPem() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + String base64EncodedKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()); + return BaseConstants.PKCS8_PRIVATE_HEADER + "\n" + base64EncodedKey + "\n" + BaseConstants.PKCS8_PRIVATE_FOOTER; + } + + /** + * Decodes (without verifying) the payload segment of a compact JWT so tests can assert + * on its claims. These tokens are self-signed with a key generated in-test, so decoding + * the payload directly is sufficient to verify claim content. + */ + private static JsonObject decodeJwtPayload(String jwt) { + String[] parts = jwt.split("\\."); + byte[] payloadBytes = Base64.getUrlDecoder().decode(parts[1]); + return JsonParser.parseString(new String(payloadBytes, StandardCharsets.UTF_8)).getAsJsonObject(); + } + + @Test + public void testGetSignedDataTokensWithValidKeyMultipleTokensTimeToLiveAndContext() { + try { + String privateKeyPem = generateValidPkcs8PrivateKeyPem(); + ArrayList tokens = new ArrayList<>(); + tokens.add("data_token_one"); + tokens.add("data_token_two"); + Map ctxMap = new HashMap<>(); + ctxMap.put("role", "admin"); + ctxMap.put("department", "finance"); + + JsonObject credentials = new JsonObject(); + credentials.addProperty("privateKey", privateKeyPem); + credentials.addProperty("clientId", "client_id_value"); + credentials.addProperty("keyId", "key_id_value"); + String credentialsJsonString = new Gson().toJson(credentials); + + int timeToLiveSeconds = 120; + long beforeCreationEpochSeconds = System.currentTimeMillis() / 1000; + List responses = SignedDataTokens.builder() + .setCredentials(credentialsJsonString) + .setDataTokens(tokens) + .setTimeToLive(timeToLiveSeconds) + .setCtx(ctxMap) + .build() + .getSignedDataTokens(); + + Assert.assertEquals(tokens.size(), responses.size()); + for (int i = 0; i < tokens.size(); i++) { + SignedDataTokenResponse response = responses.get(i); + Assert.assertEquals(tokens.get(i), response.getToken()); + Assert.assertTrue(response.getSignedToken().startsWith(BaseConstants.SIGNED_DATA_TOKEN_PREFIX)); + + String signedJwt = response.getSignedToken().substring(BaseConstants.SIGNED_DATA_TOKEN_PREFIX.length()); + JsonObject payload = decodeJwtPayload(signedJwt); + Assert.assertEquals(tokens.get(i), payload.get("tok").getAsString()); + Assert.assertEquals("key_id_value", payload.get("key").getAsString()); + Assert.assertEquals("client_id_value", payload.get("sub").getAsString()); + Assert.assertEquals("sdk", payload.get("iss").getAsString()); + + Assert.assertTrue(payload.has("ctx")); + Assert.assertEquals("admin", payload.getAsJsonObject("ctx").get("role").getAsString()); + Assert.assertEquals("finance", payload.getAsJsonObject("ctx").get("department").getAsString()); + + long expirationEpochSeconds = payload.get("exp").getAsLong(); + long expectedExpirationEpochSeconds = beforeCreationEpochSeconds + timeToLiveSeconds; + // Small allowance for time elapsed during test execution + Assert.assertTrue(Math.abs(expirationEpochSeconds - expectedExpirationEpochSeconds) <= 5); + } + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN + ": " + e); + } + } + + @Test + public void testGetSignedDataTokensWithValidKeyAndDefaultTimeToLive() { + try { + String privateKeyPem = generateValidPkcs8PrivateKeyPem(); + ArrayList tokens = new ArrayList<>(); + tokens.add("default_ttl_token"); + + JsonObject credentials = new JsonObject(); + credentials.addProperty("privateKey", privateKeyPem); + credentials.addProperty("clientId", "client_id_value"); + credentials.addProperty("keyId", "key_id_value"); + String credentialsJsonString = new Gson().toJson(credentials); + + long beforeCreationEpochSeconds = System.currentTimeMillis() / 1000; + List responses = SignedDataTokens.builder() + .setCredentials(credentialsJsonString) + .setDataTokens(tokens) + // timeToLive intentionally not set, exercising the default-60-second branch + .build() + .getSignedDataTokens(); + + Assert.assertEquals(1, responses.size()); + String signedJwt = responses.get(0).getSignedToken().substring(BaseConstants.SIGNED_DATA_TOKEN_PREFIX.length()); + JsonObject payload = decodeJwtPayload(signedJwt); + Assert.assertEquals(tokens.get(0), payload.get("tok").getAsString()); + // No context was set, so the "ctx" claim branch should be skipped entirely + Assert.assertFalse(payload.has("ctx")); + + long expirationEpochSeconds = payload.get("exp").getAsLong(); + long expectedExpirationEpochSeconds = beforeCreationEpochSeconds + 60; + Assert.assertTrue(Math.abs(expirationEpochSeconds - expectedExpirationEpochSeconds) <= 5); + } catch (Exception e) { + Assert.fail(INVALID_EXCEPTION_THROWN + ": " + e); + } + } } diff --git a/common/src/test/java/com/skyflow/utils/BaseUtilsTests.java b/common/src/test/java/com/skyflow/utils/BaseUtilsTests.java index 024bca74..bc1bd216 100644 --- a/common/src/test/java/com/skyflow/utils/BaseUtilsTests.java +++ b/common/src/test/java/com/skyflow/utils/BaseUtilsTests.java @@ -1,5 +1,6 @@ package com.skyflow.utils; +import com.google.gson.JsonObject; import com.skyflow.config.Credentials; import com.skyflow.enums.Env; import com.skyflow.errors.ErrorCode; @@ -9,7 +10,10 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.net.MalformedURLException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; public class BaseUtilsTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; @@ -135,4 +139,106 @@ public void testGenerateBearerTokenWithToken() { Assert.fail(INVALID_EXCEPTION_THROWN); } } + + @Test + public void testGetBaseURLWithMalformedURL() { + try { + BaseUtils.getBaseURL("not a url"); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (MalformedURLException e) { + // expected + } + } + + @Test + public void testGenerateBearerTokenWithCredentialsFileAndMapContext() { + try { + Map mapContext = new HashMap<>(); + mapContext.put("test_key", "test_value"); + Credentials credentials = new Credentials(); + credentials.setPath(filePath); + credentials.setContext(mapContext); + credentials.setRoles(roles); + BaseUtils.generateBearerToken(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (ClassCastException e) { + Assert.fail("Map context should not cause a ClassCastException"); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals( + BaseUtils.parameterizedString(ErrorMessage.FileNotFound.getMessage(), filePath), + e.getMessage() + ); + } + } + + @Test + public void testGenerateBearerTokenWithCredentialsStringAndMapContext() { + try { + Map mapContext = new HashMap<>(); + mapContext.put("test_key", "test_value"); + Credentials credentials = new Credentials(); + credentials.setCredentialsString(credentialsString); + credentials.setContext(mapContext); + credentials.setRoles(roles); + BaseUtils.generateBearerToken(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (ClassCastException e) { + Assert.fail("Map context should not cause a ClassCastException"); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.CredentialsStringInvalidJson.getMessage(), e.getMessage()); + } + } + + @Test + public void testGenerateBearerTokenWithContextNeitherStringNorMap() { + try { + // context is left unset (null), which is neither a String nor a Map -- this should + // simply be skipped rather than throwing any type-related exception. + Credentials credentials = new Credentials(); + credentials.setCredentialsString(credentialsString); + credentials.setRoles(roles); + BaseUtils.generateBearerToken(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (ClassCastException e) { + Assert.fail("Non String/Map context should not cause a ClassCastException"); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.CredentialsStringInvalidJson.getMessage(), e.getMessage()); + } + } + + @Test + public void testGetPrivateKeyFromPemWithMissingHeader() { + try { + BaseUtils.getPrivateKeyFromPem("this-is-not-a-pem-key-at-all"); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.JwtInvalidFormat.getMessage(), e.getMessage()); + } + } + + @Test + public void testGetPrivateKeyFromPemWithInvalidBase64Body() { + String malformedPem = "-----BEGIN PRIVATE KEY-----\nnot-valid-base64!!!\n-----END PRIVATE KEY-----"; + try { + BaseUtils.getPrivateKeyFromPem(malformedPem); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (IllegalArgumentException e) { + Assert.fail("Invalid base64 content should be wrapped into a SkyflowException, not thrown raw"); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); + Assert.assertEquals(ErrorMessage.InvalidKeySpec.getMessage(), e.getMessage()); + } + } + + @Test + public void testGetCommonMetrics() { + JsonObject metrics = BaseUtils.getCommonMetrics(); + Assert.assertNotNull(metrics.get(BaseConstants.SDK_METRIC_CLIENT_DEVICE_MODEL)); + Assert.assertNotNull(metrics.get(BaseConstants.SDK_METRIC_RUNTIME_DETAILS)); + Assert.assertNotNull(metrics.get(BaseConstants.SDK_METRIC_CLIENT_OS_DETAILS)); + } } diff --git a/common/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java b/common/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java index 9754687a..11108e4b 100644 --- a/common/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java +++ b/common/src/test/java/com/skyflow/utils/logger/LogUtilLevelTests.java @@ -96,4 +96,68 @@ public void testInfoLogSuppressedWhenLogLevelIsWarn() { .anyMatch(r -> r.getLevel().equals(Level.INFO)); Assert.assertFalse("INFO log should NOT appear when LogLevel is WARN", infoCaptured); } + + @Test + public void testDebugLogAppearsWhenLogLevelIsDebug() { + LogUtil.setupLogger(LogLevel.DEBUG); + CapturingHandler handler = attachCapture(); + + LogUtil.printDebugLog("debug message"); + + boolean debugCaptured = handler.records.stream() + .anyMatch(r -> r.getLevel().equals(Level.CONFIG) + && r.getMessage().contains("debug message")); + Assert.assertTrue("DEBUG log should appear when LogLevel is DEBUG", debugCaptured); + } + + @Test + public void testDebugLogSuppressedWhenLogLevelIsInfo() { + LogUtil.setupLogger(LogLevel.INFO); + CapturingHandler handler = attachCapture(); + + LogUtil.printDebugLog("suppressed debug message"); + + boolean debugCaptured = handler.records.stream() + .anyMatch(r -> r.getLevel().equals(Level.CONFIG)); + Assert.assertFalse("DEBUG log should NOT appear when LogLevel is INFO", debugCaptured); + } + + @Test + public void testErrorLogAppearsWhenLogLevelIsError() { + LogUtil.setupLogger(LogLevel.ERROR); + CapturingHandler handler = attachCapture(); + + LogUtil.printErrorLog("error message"); + + boolean errorCaptured = handler.records.stream() + .anyMatch(r -> r.getLevel().equals(Level.SEVERE) + && r.getMessage().contains("error message")); + Assert.assertTrue("ERROR log should appear when LogLevel is ERROR", errorCaptured); + } + + @Test + public void testErrorLogAppearsWhenLogLevelIsDebug() { + LogUtil.setupLogger(LogLevel.DEBUG); + CapturingHandler handler = attachCapture(); + + LogUtil.printErrorLog("debug level error message"); + + boolean errorCaptured = handler.records.stream() + .anyMatch(r -> r.getLevel().equals(Level.SEVERE) + && r.getMessage().contains("debug level error message")); + Assert.assertTrue("ERROR log should appear when LogLevel is DEBUG", errorCaptured); + } + + @Test + public void testNoLogsAppearWhenLogLevelIsOff() { + LogUtil.setupLogger(LogLevel.OFF); + CapturingHandler handler = attachCapture(); + + LogUtil.printErrorLog("off error message"); + LogUtil.printWarningLog("off warning message"); + LogUtil.printInfoLog("off info message"); + LogUtil.printDebugLog("off debug message"); + + Assert.assertTrue("No logs should appear when LogLevel is OFF", handler.records.isEmpty()); + } } diff --git a/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeDataTests.java b/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeDataTests.java new file mode 100644 index 00000000..08b4f9da --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeDataTests.java @@ -0,0 +1,28 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +public class BaseDetokenizeDataTests { + + @Test + public void testGetTokenReturnsConstructorValue() { + BaseDetokenizeData data = new BaseDetokenizeData("token-value"); + + Assert.assertEquals("token-value", data.getToken()); + } + + @Test + public void testNullToken() { + BaseDetokenizeData data = new BaseDetokenizeData(null); + + Assert.assertNull(data.getToken()); + } + + @Test + public void testEmptyToken() { + BaseDetokenizeData data = new BaseDetokenizeData(""); + + Assert.assertEquals("", data.getToken()); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRecordResponseTests.java b/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRecordResponseTests.java new file mode 100644 index 00000000..52992e46 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRecordResponseTests.java @@ -0,0 +1,39 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +public class BaseDetokenizeRecordResponseTests { + + @Test + public void testGettersReturnConstructorValuesOnSuccess() { + BaseDetokenizeRecordResponse response = new BaseDetokenizeRecordResponse("token-value", null); + + Assert.assertEquals("token-value", response.getToken()); + Assert.assertNull(response.getError()); + } + + @Test + public void testGettersReturnConstructorValuesOnError() { + BaseDetokenizeRecordResponse response = new BaseDetokenizeRecordResponse(null, "some error"); + + Assert.assertNull(response.getToken()); + Assert.assertEquals("some error", response.getError()); + } + + @Test + public void testBothTokenAndErrorNull() { + BaseDetokenizeRecordResponse response = new BaseDetokenizeRecordResponse(null, null); + + Assert.assertNull(response.getToken()); + Assert.assertNull(response.getError()); + } + + @Test + public void testBothTokenAndErrorPopulated() { + BaseDetokenizeRecordResponse response = new BaseDetokenizeRecordResponse("token-value", "some error"); + + Assert.assertEquals("token-value", response.getToken()); + Assert.assertEquals("some error", response.getError()); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRequestTests.java b/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRequestTests.java new file mode 100644 index 00000000..0b414353 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseDetokenizeRequestTests.java @@ -0,0 +1,24 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +public class BaseDetokenizeRequestTests { + + @Test + public void testInstantiationDoesNotThrow() { + BaseDetokenizeRequest request = new BaseDetokenizeRequest(); + + Assert.assertNotNull(request); + } + + @Test + public void testUsableAsExtensionPointForSubclasses() { + // BaseDetokenizeRequest carries no state of its own; it exists purely so module-specific + // DetokenizeRequest classes (e.g. flowvault's) can extend it. Verify the subtype relationship holds. + BaseDetokenizeRequest request = new BaseDetokenizeRequest() { + }; + + Assert.assertTrue(request instanceof BaseDetokenizeRequest); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseInsertRequestTests.java b/common/src/test/java/com/skyflow/vault/data/BaseInsertRequestTests.java new file mode 100644 index 00000000..e8ce8e06 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseInsertRequestTests.java @@ -0,0 +1,41 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +public class BaseInsertRequestTests { + + @Test + public void testBuilderSetsTable() { + BaseInsertRequest.BaseInsertRequestBuilder builder = new BaseInsertRequest.BaseInsertRequestBuilder(); + builder.table("test_table"); + BaseInsertRequest request = new BaseInsertRequest(builder); + + Assert.assertEquals("test_table", request.getTable()); + } + + @Test + public void testBuilderTableMethodReturnsSameBuilderInstance() { + BaseInsertRequest.BaseInsertRequestBuilder builder = new BaseInsertRequest.BaseInsertRequestBuilder(); + BaseInsertRequest.BaseInsertRequestBuilder returned = builder.table("test_table"); + + Assert.assertSame(builder, returned); + } + + @Test + public void testNullTableWhenNeverSet() { + BaseInsertRequest.BaseInsertRequestBuilder builder = new BaseInsertRequest.BaseInsertRequestBuilder(); + BaseInsertRequest request = new BaseInsertRequest(builder); + + Assert.assertNull(request.getTable()); + } + + @Test + public void testEmptyTable() { + BaseInsertRequest.BaseInsertRequestBuilder builder = new BaseInsertRequest.BaseInsertRequestBuilder(); + builder.table(""); + BaseInsertRequest request = new BaseInsertRequest(builder); + + Assert.assertEquals("", request.getTable()); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseInsertResponseTests.java b/common/src/test/java/com/skyflow/vault/data/BaseInsertResponseTests.java new file mode 100644 index 00000000..93b47f32 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseInsertResponseTests.java @@ -0,0 +1,69 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; + +public class BaseInsertResponseTests { + + @Test + public void testGettersReturnConstructorValues() { + ArrayList> insertedFields = new ArrayList<>(); + HashMap field = new HashMap<>(); + field.put("skyflow_id", "id-1"); + insertedFields.add(field); + + ArrayList> errors = new ArrayList<>(); + HashMap error = new HashMap<>(); + error.put("error", "some error"); + errors.add(error); + + BaseInsertResponse response = new BaseInsertResponse(insertedFields, errors); + + Assert.assertEquals(insertedFields, response.getInsertedFields()); + Assert.assertEquals(errors, response.getErrors()); + } + + @Test + public void testNullInsertedFieldsAndErrors() { + BaseInsertResponse response = new BaseInsertResponse(null, null); + + Assert.assertNull(response.getInsertedFields()); + Assert.assertNull(response.getErrors()); + } + + @Test + public void testEmptyInsertedFieldsAndErrors() { + BaseInsertResponse response = new BaseInsertResponse(new ArrayList<>(), new ArrayList<>()); + + Assert.assertTrue(response.getInsertedFields().isEmpty()); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testToStringWithPopulatedFieldsContainsValues() { + ArrayList> insertedFields = new ArrayList<>(); + HashMap field = new HashMap<>(); + field.put("skyflow_id", "id-1"); + insertedFields.add(field); + + BaseInsertResponse response = new BaseInsertResponse(insertedFields, new ArrayList<>()); + String result = response.toString(); + + Assert.assertNotNull(result); + Assert.assertTrue(result.contains("insertedFields")); + Assert.assertTrue(result.contains("skyflow_id")); + Assert.assertTrue(result.contains("id-1")); + } + + @Test + public void testToStringWithNullFieldsDoesNotThrowAndSerializesNulls() { + BaseInsertResponse response = new BaseInsertResponse(null, null); + String result = response.toString(); + + Assert.assertNotNull(result); + Assert.assertTrue(result.contains("null")); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/RequestContextTests.java b/common/src/test/java/com/skyflow/vault/data/RequestContextTests.java new file mode 100644 index 00000000..d8747425 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/RequestContextTests.java @@ -0,0 +1,68 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.CustomHeaderKey; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Map; + +public class RequestContextTests { + + @Test + public void testGetOperationReturnsConstructorValue() { + RequestContext context = new RequestContext("INSERT"); + + Assert.assertEquals("INSERT", context.getOperation()); + } + + @Test + public void testNullOperation() { + RequestContext context = new RequestContext(null); + + Assert.assertNull(context.getOperation()); + } + + @Test + public void testGetHeadersReturnsEmptyMapByDefault() { + RequestContext context = new RequestContext("INSERT"); + + Assert.assertTrue(context.getHeaders().isEmpty()); + } + + @Test + public void testAddHeaderIsReflectedInGetHeaders() { + RequestContext context = new RequestContext("INSERT"); + context.addHeader(CustomHeaderKey.SkyflowAccountID, "account-id-value"); + + Map headers = context.getHeaders(); + + Assert.assertEquals(1, headers.size()); + Assert.assertEquals("account-id-value", headers.get(CustomHeaderKey.SkyflowAccountID)); + } + + @Test + public void testAddHeaderOverwritesExistingValueForSameKey() { + RequestContext context = new RequestContext("INSERT"); + context.addHeader(CustomHeaderKey.SkyflowAccountID, "first-value"); + context.addHeader(CustomHeaderKey.SkyflowAccountID, "second-value"); + + Assert.assertEquals(1, context.getHeaders().size()); + Assert.assertEquals("second-value", context.getHeaders().get(CustomHeaderKey.SkyflowAccountID)); + } + + @Test + public void testAddMultipleDistinctHeaders() { + RequestContext context = new RequestContext("DETOKENIZE"); + context.addHeader(CustomHeaderKey.SkyflowAccountID, "account-id-value"); + context.addHeader(CustomHeaderKey.SkyflowAccountName, "account-name-value"); + + Assert.assertEquals(2, context.getHeaders().size()); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetHeadersReturnsUnmodifiableMap() { + RequestContext context = new RequestContext("INSERT"); + + context.getHeaders().put(CustomHeaderKey.RequestIDHeader, "request-id-value"); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/RequestInterceptorTests.java b/common/src/test/java/com/skyflow/vault/data/RequestInterceptorTests.java new file mode 100644 index 00000000..a03e773d --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/RequestInterceptorTests.java @@ -0,0 +1,28 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.CustomHeaderKey; +import org.junit.Assert; +import org.junit.Test; + +public class RequestInterceptorTests { + + @Test + public void testInterceptMutatesRequestContext() { + RequestInterceptor interceptor = context -> context.addHeader(CustomHeaderKey.SkyflowAccountID, "account-id-value"); + RequestContext context = new RequestContext("INSERT"); + + interceptor.intercept(context); + + Assert.assertEquals("account-id-value", context.getHeaders().get(CustomHeaderKey.SkyflowAccountID)); + } + + @Test + public void testInterceptorIsFunctionalInterfaceUsableAsLambda() { + final boolean[] invoked = {false}; + RequestInterceptor interceptor = context -> invoked[0] = true; + + interceptor.intercept(new RequestContext("DETOKENIZE")); + + Assert.assertTrue(invoked[0]); + } +} diff --git a/flowvault/src/main/java/com/skyflow/VaultClient.java b/flowvault/src/main/java/com/skyflow/VaultClient.java index 9f326349..9033e642 100644 --- a/flowvault/src/main/java/com/skyflow/VaultClient.java +++ b/flowvault/src/main/java/com/skyflow/VaultClient.java @@ -6,6 +6,7 @@ import com.skyflow.generated.rest.ApiClient; import com.skyflow.generated.rest.ApiClientBuilder; import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; +import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.utils.Utils; public class VaultClient extends BaseVaultClient { @@ -23,6 +24,10 @@ protected FlowserviceClient getRecordsApi() { return this.apiClient.flowservice(); } + protected RecordsClient getQueryApi() { + return this.apiClient.records(); + } + protected void setCommonCredentials(Credentials commonCredentials) throws SkyflowException { this.commonCredentials = commonCredentials; super.prioritiseCredentials(this.vaultConfig.getCredentials()); diff --git a/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java b/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java index 1dcf86b6..475f8ad2 100644 --- a/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java +++ b/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java @@ -4,7 +4,9 @@ public enum InterfaceName { INSERT("insert"), DETOKENIZE("detokenize"), DELETE("delete tokens"), - TOKENIZE("tokenize"); + TOKENIZE("tokenize"), + QUERY("query"), + GET("get"); private final String interfaceName; diff --git a/flowvault/src/main/java/com/skyflow/utils/Utils.java b/flowvault/src/main/java/com/skyflow/utils/Utils.java index 5880344b..e26286c0 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Utils.java +++ b/flowvault/src/main/java/com/skyflow/utils/Utils.java @@ -10,7 +10,9 @@ import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; +import com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest; import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; +import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; import com.skyflow.generated.rest.types.*; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; @@ -864,4 +866,121 @@ public static BulkTokenizeResponse formatBulkTokenizeResponse( } return null; } + + public static V1ExecuteQueryRequest getQueryRequestBody(QueryRequest request, String vaultId) { + return V1ExecuteQueryRequest.builder() + .vaultId(vaultId) + .query(request.getQuery()) + .build(); + } + + public static QueryResponse buildQueryResponse(V1ExecuteQueryResponse res) { + ArrayList> fields = new ArrayList<>(); + if (res != null && res.getRecords().isPresent()) { + for (V1ExecuteQueryRecordResponse record : res.getRecords().get()) { + HashMap fieldMap = new HashMap<>(); + if (record.getData().isPresent()) { + fieldMap.putAll(record.getData().get()); + } + fields.add(fieldMap); + } + } + return new QueryResponse(fields); + } + + private static List buildColumnRedactions(List columnRedactions) { + List columnRedactionsList = new ArrayList<>(); + for (ColumnRedaction columnRedaction : columnRedactions) { + columnRedactionsList.add(V1ColumnRedactions.builder() + .columnName(columnRedaction.getColumnName()) + .redaction(columnRedaction.getRedaction()) + .build()); + } + return columnRedactionsList; + } + + private static List buildUniqueValues(List> uniqueValues) { + List uniqueValuesList = new ArrayList<>(); + for (Map uniqueValue : uniqueValues) { + uniqueValuesList.add(V1UniqueValue.builder().data(uniqueValue).build()); + } + return uniqueValuesList; + } + + public static V1GetRequest getGetRequestBody(GetRequest request, String vaultId) { + V1GetRequest.Builder builder = V1GetRequest.builder().vaultId(vaultId); + + if (request.getRecords() != null && !request.getRecords().isEmpty()) { + List recordsList = new ArrayList<>(); + for (GetRecordRequest record : request.getRecords()) { + V1GetRequestData.Builder recordBuilder = V1GetRequestData.builder() + .tableName(record.getTable()); + if (record.getIds() != null) { + recordBuilder.skyflowIDs(record.getIds()); + } + if (record.getFields() != null) { + recordBuilder.columns(record.getFields()); + } + if (record.getColumnRedactions() != null && !record.getColumnRedactions().isEmpty()) { + recordBuilder.columnRedactions(buildColumnRedactions(record.getColumnRedactions())); + } + if (record.getUniqueValues() != null && !record.getUniqueValues().isEmpty()) { + recordBuilder.uniqueValues(buildUniqueValues(record.getUniqueValues())); + } + recordsList.add(recordBuilder.build()); + } + builder.records(recordsList); + } else { + builder.tableName(request.getTable()); + if (request.getIds() != null) { + builder.skyflowIDs(request.getIds()); + } + if (request.getFields() != null) { + builder.columns(request.getFields()); + } + if (request.getColumnRedactions() != null && !request.getColumnRedactions().isEmpty()) { + builder.columnRedactions(buildColumnRedactions(request.getColumnRedactions())); + } + if (request.getUniqueValues() != null && !request.getUniqueValues().isEmpty()) { + builder.uniqueValues(buildUniqueValues(request.getUniqueValues())); + } + } + + if (request.getLimit() != null) { + builder.limit(request.getLimit()); + } + if (request.getOffset() != null) { + builder.offset(request.getOffset()); + } + return builder.build(); + } + + public static GetResponse buildGetResponse(V1GetResponse res) { + ArrayList> data = new ArrayList<>(); + ArrayList> errors = new ArrayList<>(); + if (res != null && res.getRecords().isPresent()) { + for (V1RecordResponseObject record : res.getRecords().get()) { + if (record.getError().isPresent()) { + HashMap errorRecord = new HashMap<>(); + record.getSkyflowId().ifPresent(skyflowId -> errorRecord.put("skyflowId", skyflowId)); + record.getTableName().ifPresent(tableName -> errorRecord.put("tableName", tableName)); + errorRecord.put("error", record.getError().get()); + record.getHttpCode().ifPresent(httpCode -> errorRecord.put("httpCode", httpCode)); + errors.add(errorRecord); + } else { + HashMap getRecord = new HashMap<>(); + if (record.getData().isPresent()) { + getRecord.putAll(record.getData().get()); + } + record.getSkyflowId().ifPresent(skyflowId -> getRecord.put("skyflowId", skyflowId)); + record.getTableName().ifPresent(tableName -> getRecord.put("tableName", tableName)); + if (record.getTokens().isPresent()) { + getRecord.putAll(record.getTokens().get()); + } + data.add(getRecord); + } + } + } + return new GetResponse(data, errors); + } } diff --git a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java index 1d0228ed..6896e6fe 100644 --- a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java @@ -620,4 +620,165 @@ public static void validateBulkTokenizeRequest(BulkTokenizeRequest request) thro } } + public static void validateQueryRequest(QueryRequest queryRequest) throws SkyflowException { + String query = queryRequest.getQuery(); + if (query == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.QUERY_IS_REQUIRED.getLog(), InterfaceName.QUERY.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.QueryKeyError.getMessage()); + } else if (query.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_QUERY.getLog(), InterfaceName.QUERY.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyQuery.getMessage()); + } + } + + public static void validateGetRequest(GetRequest getRequest) throws SkyflowException { + String table = getRequest.getTable(); + ArrayList ids = getRequest.getIds(); + ArrayList fields = getRequest.getFields(); + List> uniqueValues = getRequest.getUniqueValues(); + List columnRedactions = getRequest.getColumnRedactions(); + List records = getRequest.getRecords(); + + boolean hasSingleTableFields = table != null || ids != null || fields != null + || uniqueValues != null || columnRedactions != null; + boolean hasRecords = records != null && !records.isEmpty(); + + if (hasRecords) { + if (hasSingleTableFields) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.BOTH_SINGLE_TABLE_FIELDS_AND_RECORDS_PASSED.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.BothSingleTableFieldsAndRecordsSpecified.getMessage()); + } + for (GetRecordRequest record : records) { + if (record == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.NULL_GET_RECORD_REQUEST_OBJECT.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullGetRecordRequest.getMessage()); + } + validateSingleTableLookup(record.getTable(), record.getIds(), record.getFields(), + record.getUniqueValues(), record.getColumnRedactions()); + } + } else { + validateSingleTableLookup(table, ids, fields, uniqueValues, columnRedactions); + } + } + + private static void validateSingleTableLookup( + String table, ArrayList ids, ArrayList fields, + List> uniqueValues, List columnRedactions + ) throws SkyflowException { + if (table == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.TABLE_IS_REQUIRED.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.TableKeyError.getMessage()); + } else if (table.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_TABLE_NAME.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTable.getMessage()); + } + + if (ids != null) { + if (ids.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_IDS.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyIds.getMessage()); + } else { + for (int index = 0; index < ids.size(); index++) { + String id = ids.get(index); + if (id == null || id.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_ID_IN_IDS.getLog(), + InterfaceName.GET.getName(), String.valueOf(index) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyIdInIds.getMessage()); + } + } + } + } + + if (fields != null) { + if (fields.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_FIELDS.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyFields.getMessage()); + } else { + for (int index = 0; index < fields.size(); index++) { + String field = fields.get(index); + if (field == null || field.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_FIELD_IN_FIELDS.getLog(), + InterfaceName.GET.getName(), String.valueOf(index) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyFieldInFields.getMessage()); + } + } + } + } + + if (ids == null && uniqueValues == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.NEITHER_IDS_NOR_UNIQUE_VALUES_PASSED.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.IdsOrUniqueValuesKeyError.getMessage()); + } else if (ids != null && uniqueValues != null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.BOTH_IDS_AND_UNIQUE_VALUES_PASSED.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.BothIdsAndUniqueValuesSpecified.getMessage()); + } else if (uniqueValues != null) { + if (uniqueValues.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_UNIQUE_VALUES.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyUniqueValues.getMessage()); + } else { + for (int index = 0; index < uniqueValues.size(); index++) { + Map uniqueValue = uniqueValues.get(index); + if (uniqueValue == null || uniqueValue.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_UNIQUE_VALUE_IN_UNIQUE_VALUES.getLog(), + InterfaceName.GET.getName(), String.valueOf(index) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyUniqueValueInUniqueValues.getMessage()); + } + } + } + } + + if (columnRedactions != null && !columnRedactions.isEmpty()) { + for (ColumnRedaction columnRedaction : columnRedactions) { + if (columnRedaction == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.NULL_COLUMN_REDACTION_OBJECT.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullColumnRedactions.getMessage()); + } + String columnName = columnRedaction.getColumnName(); + String redaction = columnRedaction.getRedaction(); + if (columnName == null || columnName.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.NULL_COLUMN_NAME_IN_COLUMN_REDACTION.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullColumnNameInColumnRedaction.getMessage()); + } + if (redaction == null || redaction.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_OR_NULL_REDACTION_IN_COLUMN_REDACTION.getLog(), InterfaceName.GET.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.NullRedactionInColumnRedaction.getMessage()); + } + } + } + } + } diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java index 476ce9d5..342346e8 100644 --- a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -188,6 +188,72 @@ public DeleteTokensResponse deleteTokens(DeleteTokensRequest request, DeleteToke } } + public QueryResponse query(QueryRequest queryRequest) throws SkyflowException { + return query(queryRequest, null); + } + + public QueryResponse query(QueryRequest queryRequest, QueryOptions options) throws SkyflowException { + try { + LogUtil.printInfoLog(InfoLogs.QUERY_TRIGGERED.getLog()); + LogUtil.printInfoLog(InfoLogs.VALIDATING_QUERY_REQUEST.getLog()); + Validations.validateQueryRequest(queryRequest); + setBearerToken(); + + com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest requestBody = + getQueryRequestBody(queryRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("QUERY"); + if (interceptor != null) interceptor.intercept(ctx); + com.skyflow.generated.rest.types.V1ExecuteQueryResponse response = + this.getQueryApi().withRawResponse().flowServiceExecuteQuery(requestBody, buildRequestOptions(ctx)).body(); + LogUtil.printInfoLog(InfoLogs.QUERY_REQUEST_RESOLVED.getLog()); + + QueryResponse queryResponse = buildQueryResponse(response); + LogUtil.printInfoLog(InfoLogs.QUERY_SUCCESS.getLog()); + return queryResponse; + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.QUERY_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.QUERY_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } + } + + public GetResponse get(GetRequest getRequest) throws SkyflowException { + return get(getRequest, null); + } + + public GetResponse get(GetRequest getRequest, GetOptions options) throws SkyflowException { + try { + LogUtil.printInfoLog(InfoLogs.GET_TRIGGERED.getLog()); + LogUtil.printInfoLog(InfoLogs.VALIDATE_GET_REQUEST.getLog()); + Validations.validateGetRequest(getRequest); + setBearerToken(); + + com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest requestBody = + getGetRequestBody(getRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("GET"); + if (interceptor != null) interceptor.intercept(ctx); + com.skyflow.generated.rest.types.V1GetResponse response = + this.getRecordsApi().withRawResponse().get(requestBody, buildRequestOptions(ctx)).body(); + LogUtil.printInfoLog(InfoLogs.GET_REQUEST_RESOLVED.getLog()); + + GetResponse getResponse = buildGetResponse(response); + LogUtil.printInfoLog(InfoLogs.GET_SUCCESS.getLog()); + return getResponse; + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(e.body()); + LogUtil.printErrorLog(ErrorLogs.GET_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.GET_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.getMessage()); + } + } + // ── Bulk Insert ─────────────────────────────────────────────────────────── public BulkInsertResponse bulkInsert(BulkInsertRequest insertRequest) throws SkyflowException { diff --git a/flowvault/src/main/java/com/skyflow/vault/data/ColumnRedaction.java b/flowvault/src/main/java/com/skyflow/vault/data/ColumnRedaction.java new file mode 100644 index 00000000..2325c0ac --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/ColumnRedaction.java @@ -0,0 +1,40 @@ +package com.skyflow.vault.data; + +public class ColumnRedaction { + private final ColumnRedactionBuilder builder; + + private ColumnRedaction(ColumnRedactionBuilder builder) { + this.builder = builder; + } + + public String getColumnName() { + return this.builder.columnName; + } + + public String getRedaction() { + return this.builder.redaction; + } + + public static ColumnRedactionBuilder builder() { + return new ColumnRedactionBuilder(); + } + + public static final class ColumnRedactionBuilder { + private String columnName; + private String redaction; + + public ColumnRedactionBuilder columnName(String columnName) { + this.columnName = columnName; + return this; + } + + public ColumnRedactionBuilder redaction(String redaction) { + this.redaction = redaction; + return this; + } + + public ColumnRedaction build() { + return new ColumnRedaction(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/GetOptions.java new file mode 100644 index 00000000..b4dbc096 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetOptions.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.data; + +public final class GetOptions { + private final RequestInterceptor interceptor; + + private GetOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public GetOptions build() { + return new GetOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetRecordRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/GetRecordRequest.java new file mode 100644 index 00000000..d2f4c035 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetRecordRequest.java @@ -0,0 +1,71 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * A single table's lookup within a multi-table {@link GetRequest#getRecords()} batch. + * Mirrors the shape of a single-table {@link GetRequest}, minus the request-wide + * {@code limit}/{@code offset}. + */ +public class GetRecordRequest extends BaseGetRequest { + private final GetRecordRequestBuilder builder; + + private GetRecordRequest(GetRecordRequestBuilder builder) { + super(builder); + this.builder = builder; + } + + public static GetRecordRequestBuilder builder() { + return new GetRecordRequestBuilder(); + } + + public List getColumnRedactions() { + return this.builder.columnRedactions; + } + + public List> getUniqueValues() { + return this.builder.uniqueValues; + } + + public static final class GetRecordRequestBuilder extends BaseGetRequestBuilder { + private List columnRedactions; + private List> uniqueValues; + + private GetRecordRequestBuilder() { + } + + @Override + public GetRecordRequestBuilder table(String table) { + super.table(table); + return this; + } + + @Override + public GetRecordRequestBuilder ids(ArrayList ids) { + super.ids(ids); + return this; + } + + @Override + public GetRecordRequestBuilder fields(ArrayList fields) { + super.fields(fields); + return this; + } + + public GetRecordRequestBuilder columnRedactions(List columnRedactions) { + this.columnRedactions = columnRedactions; + return this; + } + + public GetRecordRequestBuilder uniqueValues(List> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + public GetRecordRequest build() { + return new GetRecordRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/GetRequest.java new file mode 100644 index 00000000..c4e05c1f --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetRequest.java @@ -0,0 +1,102 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class GetRequest extends BaseGetRequest { + private final GetRequestBuilder builder; + + private GetRequest(GetRequestBuilder builder) { + super(builder); + this.builder = builder; + } + + public static GetRequestBuilder builder() { + return new GetRequestBuilder(); + } + + public List getColumnRedactions() { + return this.builder.columnRedactions; + } + + public List> getUniqueValues() { + return this.builder.uniqueValues; + } + + public Integer getLimit() { + return this.builder.limit; + } + + public Integer getOffset() { + return this.builder.offset; + } + + /** + * A multi-table lookup batch — when set, this request fetches from each listed + * table in a single call instead of the single-table fields ({@code table}, {@code ids}, + * {@code fields}, {@code uniqueValues}, {@code columnRedactions}) above. The two modes + * are mutually exclusive. + */ + public List getRecords() { + return this.builder.records; + } + + public static final class GetRequestBuilder extends BaseGetRequestBuilder { + private List columnRedactions; + private List> uniqueValues; + private Integer limit; + private Integer offset; + private List records; + + private GetRequestBuilder() { + } + + @Override + public GetRequestBuilder table(String table) { + super.table(table); + return this; + } + + @Override + public GetRequestBuilder ids(ArrayList ids) { + super.ids(ids); + return this; + } + + @Override + public GetRequestBuilder fields(ArrayList fields) { + super.fields(fields); + return this; + } + + public GetRequestBuilder columnRedactions(List columnRedactions) { + this.columnRedactions = columnRedactions; + return this; + } + + public GetRequestBuilder uniqueValues(List> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + public GetRequestBuilder limit(Integer limit) { + this.limit = limit; + return this; + } + + public GetRequestBuilder offset(Integer offset) { + this.offset = offset; + return this; + } + + public GetRequestBuilder records(List records) { + this.records = records; + return this; + } + + public GetRequest build() { + return new GetRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/GetResponse.java new file mode 100644 index 00000000..4267dba3 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetResponse.java @@ -0,0 +1,10 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.HashMap; + +public class GetResponse extends BaseGetResponse { + public GetResponse(ArrayList> data, ArrayList> errors) { + super(data, errors); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/QueryOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/QueryOptions.java new file mode 100644 index 00000000..86e5f725 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/QueryOptions.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.data; + +public final class QueryOptions { + private final RequestInterceptor interceptor; + + private QueryOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public QueryOptions build() { + return new QueryOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/QueryRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/QueryRequest.java new file mode 100644 index 00000000..ea27f5d1 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/QueryRequest.java @@ -0,0 +1,26 @@ +package com.skyflow.vault.data; + +public class QueryRequest extends BaseQueryRequest { + private QueryRequest(QueryRequestBuilder builder) { + super(builder); + } + + public static QueryRequestBuilder builder() { + return new QueryRequestBuilder(); + } + + public static final class QueryRequestBuilder extends BaseQueryRequestBuilder { + private QueryRequestBuilder() { + } + + @Override + public QueryRequestBuilder query(String query) { + super.query(query); + return this; + } + + public QueryRequest build() { + return new QueryRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/QueryResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/QueryResponse.java new file mode 100644 index 00000000..2e242d1a --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/QueryResponse.java @@ -0,0 +1,10 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.HashMap; + +public class QueryResponse extends BaseQueryResponse { + public QueryResponse(ArrayList> fields) { + super(fields); + } +} diff --git a/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java index d5214913..dbfdfbf4 100644 --- a/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java @@ -48,9 +48,16 @@ import com.skyflow.vault.data.TokenizeRecord; import com.skyflow.vault.data.TokenizeRequest; import com.skyflow.vault.data.TokenizeResponse; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -60,6 +67,24 @@ public class UtilsTests { + private static final String ENV_FILE = ".env"; + private byte[] originalEnvContent; + + @Before + public void saveEnvFileState() throws IOException { + File f = new File(ENV_FILE); + originalEnvContent = f.exists() ? Files.readAllBytes(Paths.get(ENV_FILE)) : null; + } + + @After + public void restoreEnvFile() throws IOException { + if (originalEnvContent != null) { + Files.write(Paths.get(ENV_FILE), originalEnvContent); + } else { + Files.deleteIfExists(Paths.get(ENV_FILE)); + } + } + // ── getVaultURL ─────────────────────────────────────────────────────────── @Test @@ -108,6 +133,36 @@ public void testGetEnvVaultURL_doesNotThrowUnexpectedException() { } } + @Test + public void testGetEnvVaultURL_emptyValueThrowsEmptyVaultUrl() throws Exception { + // No VAULT_URL system/real env var is set in the test environment, so this + // exercises the Dotenv.load() fallback path with an empty value. + try (FileWriter fw = new FileWriter(ENV_FILE)) { + fw.write("VAULT_URL=\n"); + } + + try { + Utils.getEnvVaultURL(); + Assert.fail("Should have thrown SkyflowException for empty VAULT_URL"); + } catch (SkyflowException e) { + Assert.assertEquals(com.skyflow.errors.ErrorMessage.EmptyVaultUrl.getMessage(), e.getMessage()); + } + } + + @Test + public void testGetEnvVaultURL_invalidFormatThrowsInvalidVaultUrlFormat() throws Exception { + try (FileWriter fw = new FileWriter(ENV_FILE)) { + fw.write("VAULT_URL=http://example.com\n"); + } + + try { + Utils.getEnvVaultURL(); + Assert.fail("Should have thrown SkyflowException for invalid VAULT_URL format"); + } catch (SkyflowException e) { + Assert.assertEquals(com.skyflow.errors.ErrorMessage.InvalidVaultUrlFormat.getMessage(), e.getMessage()); + } + } + // ── isValidURL ──────────────────────────────────────────────────────────── @Test @@ -125,6 +180,11 @@ public void testIsValidURL_malformedUrl() { Assert.assertFalse(Utils.isValidURL("not a url")); } + @Test + public void testIsValidURL_httpsUrlWithEmptyHostIsInvalid() { + Assert.assertFalse(Utils.isValidURL("https:///path")); + } + // ── generateBearerToken ─────────────────────────────────────────────────── @Test @@ -852,6 +912,28 @@ public void testCreateErrorRecord_nullMapReturnsNull() { Assert.assertNull(Utils.createErrorRecord(null, 0, null)); } + @Test + public void testCreateErrorRecord_noCodeKeyDefaultsTo500() { + Map recordMap = new HashMap<>(); + recordMap.put("error", "something went wrong"); + + ErrorRecord err = Utils.createErrorRecord(recordMap, 1, "req-2"); + + Assert.assertEquals(500, err.getCode()); + Assert.assertEquals("something went wrong", err.getError()); + } + + @Test + public void testCreateErrorRecord_noErrorOrMessageKeyDefaultsToUnknownError() { + Map recordMap = new HashMap<>(); + recordMap.put("http_code", 403); + + ErrorRecord err = Utils.createErrorRecord(recordMap, 3, null); + + Assert.assertEquals(403, err.getCode()); + Assert.assertEquals("Unknown error", err.getError()); + } + // ── handleBulkInsertBatchException ──────────────────────────────────────── @Test @@ -887,6 +969,21 @@ public void testHandleBulkInsertBatchException_apiExceptionWithNoParsableBody() Assert.assertEquals("insert failed", errors.get(0).getError()); } + @Test + public void testHandleBulkInsertBatchException_apiExceptionWithErrorKeyBody() { + Map body = new HashMap<>(); + body.put("error", "top level auth error"); + ApiClientApiException apiEx = new ApiClientApiException("insert failed", 401, body); + RuntimeException wrapper = new RuntimeException(apiEx); + + List batch = Collections.singletonList(V1InsertRecordData.builder().data(new HashMap<>()).build()); + List errors = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(401, errors.get(0).getCode()); + Assert.assertEquals("top level auth error", errors.get(0).getError()); + } + @Test public void testHandleBulkInsertBatchException_genericException() { RuntimeException ex = new RuntimeException("boom"); @@ -902,6 +999,27 @@ public void testHandleBulkInsertBatchException_genericException() { // ── handleBulkDetokenizeBatchException ──────────────────────────────────── + @Test + public void testHandleBulkDetokenizeBatchException_apiExceptionWithResponseBody() { + Map errorRecordMap = new HashMap<>(); + errorRecordMap.put("error", "token not found"); + errorRecordMap.put("httpCode", 404); + Map body = new HashMap<>(); + body.put("response", Collections.singletonList(errorRecordMap)); + ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 404, body); + RuntimeException wrapper = new RuntimeException(apiEx); + + V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + .vaultId("vault123") + .tokens(Collections.singletonList("t1")) + .build(); + List errors = Utils.handleBulkDetokenizeBatchException(wrapper, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(404, errors.get(0).getCode()); + Assert.assertEquals("token not found", errors.get(0).getError()); + } + @Test public void testHandleBulkDetokenizeBatchException_genericException() { RuntimeException ex = new RuntimeException("boom"); @@ -939,6 +1057,24 @@ public void testHandleBulkDeleteTokensBatchException_apiExceptionWithTokensBody( Assert.assertEquals("not found", errors.get(0).getError()); } + @Test + public void testHandleBulkDeleteTokensBatchException_apiExceptionWithErrorKeyBody() { + Map body = new HashMap<>(); + body.put("error", "top level delete error"); + ApiClientApiException apiEx = new ApiClientApiException("delete failed", 403, body); + RuntimeException wrapper = new RuntimeException(apiEx); + + V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + .vaultId("vault123") + .tokens(Collections.singletonList("t1")) + .build(); + List errors = Utils.handleBulkDeleteTokensBatchException(wrapper, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(403, errors.get(0).getCode()); + Assert.assertEquals("top level delete error", errors.get(0).getError()); + } + @Test public void testHandleBulkDeleteTokensBatchException_genericException() { RuntimeException ex = new RuntimeException("boom"); @@ -955,6 +1091,27 @@ public void testHandleBulkDeleteTokensBatchException_genericException() { // ── handleBulkTokenizeBatchException ─────────────────────────────────────── + @Test + public void testHandleBulkTokenizeBatchException_apiExceptionWithResponseBody() { + Map errorRecordMap = new HashMap<>(); + errorRecordMap.put("error", "invalid value"); + errorRecordMap.put("httpCode", 400); + Map body = new HashMap<>(); + body.put("response", Collections.singletonList(errorRecordMap)); + ApiClientApiException apiEx = new ApiClientApiException("tokenize failed", 400, body); + RuntimeException wrapper = new RuntimeException(apiEx); + + V1FlowTokenizeRequest batch = V1FlowTokenizeRequest.builder() + .vaultId("vault123") + .data(Collections.singletonList(com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject.builder().value("v1").build())) + .build(); + List errors = Utils.handleBulkTokenizeBatchException(wrapper, batch, 0, 50); + + Assert.assertEquals(1, errors.size()); + Assert.assertEquals(400, errors.get(0).getCode()); + Assert.assertEquals("invalid value", errors.get(0).getError()); + } + @Test public void testHandleBulkTokenizeBatchException_genericException() { RuntimeException ex = new RuntimeException("boom"); @@ -1082,6 +1239,23 @@ public void testFormatBulkDeleteTokensResponse_error() { Assert.assertEquals(404, result.getErrors().get(0).getCode()); } + @Test + public void testFormatBulkDeleteTokensResponse_errorTextWithoutHttpCodeTreatedAsSuccess() { + V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + .value("token1") + .error("transient warning") + .build(); + V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + .tokens(Collections.singletonList(record)) + .build(); + + BulkDeleteTokensResponse result = Utils.formatBulkDeleteTokensResponse(response, 0, 50, new HashMap<>()); + + Assert.assertTrue(result.getErrors().isEmpty()); + Assert.assertEquals(1, result.getSuccess().size()); + Assert.assertEquals("token1", result.getSuccess().get(0).getToken()); + } + @Test public void testFormatBulkDeleteTokensResponse_emptyResponseReturnsNull() { V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder().build(); @@ -1147,4 +1321,244 @@ public void testFormatBulkTokenizeResponse_emptyResponseReturnsNull() { V1FlowTokenizeRequest batchRequest = V1FlowTokenizeRequest.builder().vaultId("vault123").build(); Assert.assertNull(Utils.formatBulkTokenizeResponse(response, batchRequest, 0, 50, new HashMap<>())); } + + // ── getQueryRequestBody ──────────────────────────────────────────────────── + + @Test + public void testGetQueryRequestBody_buildsCorrectRequest() { + com.skyflow.vault.data.QueryRequest request = com.skyflow.vault.data.QueryRequest.builder() + .query("SELECT * FROM table1") + .build(); + + com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest body = + Utils.getQueryRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals("SELECT * FROM table1", body.getQuery().get()); + } + + // ── buildQueryResponse ───────────────────────────────────────────────────── + + @Test + public void testBuildQueryResponse_success() { + Map data = new HashMap<>(); + data.put("skyflowId", "sky-id-1"); + data.put("name", "john"); + com.skyflow.generated.rest.types.V1ExecuteQueryRecordResponse record = + com.skyflow.generated.rest.types.V1ExecuteQueryRecordResponse.builder().data(data).build(); + com.skyflow.generated.rest.types.V1ExecuteQueryResponse response = + com.skyflow.generated.rest.types.V1ExecuteQueryResponse.builder() + .records(Collections.singletonList(record)) + .build(); + + com.skyflow.vault.data.QueryResponse result = Utils.buildQueryResponse(response); + + Assert.assertEquals(1, result.getFields().size()); + Assert.assertEquals("sky-id-1", result.getFields().get(0).get("skyflowId")); + Assert.assertEquals("john", result.getFields().get(0).get("name")); + Assert.assertNull(result.getErrors()); + } + + @Test + public void testBuildQueryResponse_emptyResponse() { + com.skyflow.generated.rest.types.V1ExecuteQueryResponse response = + com.skyflow.generated.rest.types.V1ExecuteQueryResponse.builder().build(); + + com.skyflow.vault.data.QueryResponse result = Utils.buildQueryResponse(response); + + Assert.assertTrue(result.getFields().isEmpty()); + } + + @Test + public void testBuildQueryResponse_nullResponse() { + com.skyflow.vault.data.QueryResponse result = Utils.buildQueryResponse(null); + + Assert.assertTrue(result.getFields().isEmpty()); + } + + // ── getGetRequestBody ────────────────────────────────────────────────────── + + @Test + public void testGetGetRequestBody_withIds() { + ArrayList ids = new ArrayList<>(); + ids.add("id1"); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(ids) + .build(); + + com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest body = + Utils.getGetRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals("table1", body.getTableName().get()); + Assert.assertEquals(ids, body.getSkyflowIDs().get()); + Assert.assertFalse(body.getUniqueValues().isPresent()); + Assert.assertFalse(body.getColumnRedactions().isPresent()); + } + + @Test + public void testGetGetRequestBody_withUniqueValuesAndColumnRedactions() { + Map uniqueValue = new HashMap<>(); + uniqueValue.put("email", "john@example.com"); + List> uniqueValues = Collections.singletonList(uniqueValue); + + com.skyflow.vault.data.ColumnRedaction redaction = com.skyflow.vault.data.ColumnRedaction.builder() + .columnName("email") + .redaction("MASKED") + .build(); + + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .uniqueValues(uniqueValues) + .columnRedactions(Collections.singletonList(redaction)) + .fields(new ArrayList<>(Collections.singletonList("name"))) + .limit(10) + .offset(0) + .build(); + + com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest body = + Utils.getGetRequestBody(request, "vault123"); + + Assert.assertTrue(body.getUniqueValues().isPresent()); + Assert.assertEquals(uniqueValue, body.getUniqueValues().get().get(0).getData().get()); + Assert.assertTrue(body.getColumnRedactions().isPresent()); + Assert.assertEquals("email", body.getColumnRedactions().get().get(0).getColumnName().get()); + Assert.assertEquals("MASKED", body.getColumnRedactions().get().get(0).getRedaction().get()); + Assert.assertEquals(Collections.singletonList("name"), body.getColumns().get()); + Assert.assertEquals(Integer.valueOf(10), body.getLimit().get()); + Assert.assertEquals(Integer.valueOf(0), body.getOffset().get()); + } + + // ── buildGetResponse ─────────────────────────────────────────────────────── + + @Test + public void testBuildGetResponse_success() { + Map data = new HashMap<>(); + data.put("name", "john"); + V1RecordResponseObject record = V1RecordResponseObject.builder() + .skyflowId("sky-id-1") + .data(data) + .build(); + com.skyflow.generated.rest.types.V1GetResponse response = + com.skyflow.generated.rest.types.V1GetResponse.builder() + .records(Collections.singletonList(record)) + .build(); + + com.skyflow.vault.data.GetResponse result = Utils.buildGetResponse(response); + + Assert.assertEquals(1, result.getData().size()); + Assert.assertEquals("sky-id-1", result.getData().get(0).get("skyflowId")); + Assert.assertEquals("john", result.getData().get(0).get("name")); + Assert.assertTrue(result.getErrors().isEmpty()); + } + + @Test + public void testBuildGetResponse_error() { + V1RecordResponseObject record = V1RecordResponseObject.builder() + .skyflowId("sky-id-1") + .error("not found") + .httpCode(404) + .build(); + com.skyflow.generated.rest.types.V1GetResponse response = + com.skyflow.generated.rest.types.V1GetResponse.builder() + .records(Collections.singletonList(record)) + .build(); + + com.skyflow.vault.data.GetResponse result = Utils.buildGetResponse(response); + + Assert.assertTrue(result.getData().isEmpty()); + Assert.assertEquals(1, result.getErrors().size()); + Assert.assertEquals("not found", result.getErrors().get(0).get("error")); + Assert.assertEquals(404, result.getErrors().get(0).get("httpCode")); + } + + @Test + public void testBuildGetResponse_nullResponse() { + com.skyflow.vault.data.GetResponse result = Utils.buildGetResponse(null); + + Assert.assertTrue(result.getData().isEmpty()); + Assert.assertTrue(result.getErrors().isEmpty()); + } + + @Test + public void testBuildGetResponse_successIncludesTableName() { + Map data = new HashMap<>(); + data.put("name", "john"); + V1RecordResponseObject record = V1RecordResponseObject.builder() + .skyflowId("sky-id-1") + .tableName("table1") + .data(data) + .build(); + com.skyflow.generated.rest.types.V1GetResponse response = + com.skyflow.generated.rest.types.V1GetResponse.builder() + .records(Collections.singletonList(record)) + .build(); + + com.skyflow.vault.data.GetResponse result = Utils.buildGetResponse(response); + + Assert.assertEquals("table1", result.getData().get(0).get("tableName")); + } + + // ── getGetRequestBody (multi-table records) ─────────────────────────────── + + @Test + public void testGetGetRequestBody_withRecords_buildsMultiTableRequest() { + com.skyflow.vault.data.GetRecordRequest record1 = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .build(); + Map uniqueValue = new HashMap<>(); + uniqueValue.put("email", "john@example.com"); + com.skyflow.vault.data.ColumnRedaction redaction = com.skyflow.vault.data.ColumnRedaction.builder() + .columnName("email") + .redaction("MASKED") + .build(); + com.skyflow.vault.data.GetRecordRequest record2 = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table2") + .uniqueValues(Collections.singletonList(uniqueValue)) + .columnRedactions(Collections.singletonList(redaction)) + .build(); + + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .records(java.util.Arrays.asList(record1, record2)) + .build(); + + com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest body = + Utils.getGetRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertFalse(body.getTableName().isPresent()); + Assert.assertTrue(body.getRecords().isPresent()); + Assert.assertEquals(2, body.getRecords().get().size()); + + com.skyflow.generated.rest.types.V1GetRequestData data1 = body.getRecords().get().get(0); + Assert.assertEquals("table1", data1.getTableName().get()); + Assert.assertEquals(Collections.singletonList("id1"), data1.getSkyflowIDs().get()); + + com.skyflow.generated.rest.types.V1GetRequestData data2 = body.getRecords().get().get(1); + Assert.assertEquals("table2", data2.getTableName().get()); + Assert.assertEquals(uniqueValue, data2.getUniqueValues().get().get(0).getData().get()); + Assert.assertEquals("email", data2.getColumnRedactions().get().get(0).getColumnName().get()); + Assert.assertEquals("MASKED", data2.getColumnRedactions().get().get(0).getRedaction().get()); + } + + @Test + public void testGetGetRequestBody_withRecords_topLevelLimitOffsetStillApply() { + com.skyflow.vault.data.GetRecordRequest record = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .build(); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .records(Collections.singletonList(record)) + .limit(5) + .offset(1) + .build(); + + com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest body = + Utils.getGetRequestBody(request, "vault123"); + + Assert.assertEquals(Integer.valueOf(5), body.getLimit().get()); + Assert.assertEquals(Integer.valueOf(1), body.getOffset().get()); + } } diff --git a/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java index 72ae2293..0980e08c 100644 --- a/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Test; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -326,6 +327,114 @@ public void testValidateCredentials_emptyRoles() { } } + @Test + public void testValidateCredentials_blankEntryInRoles() { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + ArrayList roles = new ArrayList<>(); + roles.add("validRole"); + roles.add(" "); + credentials.setRoles(roles); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_emptyPath() { + Credentials credentials = new Credentials(); + credentials.setPath(""); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_emptyCredentialsString() { + Credentials credentials = new Credentials(); + credentials.setCredentialsString(""); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_emptyToken() { + Credentials credentials = new Credentials(); + credentials.setToken(""); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_emptyStringContext() { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + credentials.setContext(""); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_emptyMapContext() { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + credentials.setContext(new HashMap<>()); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_invalidMapKeyContext() { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + Map context = new HashMap<>(); + context.put("invalid-key!", "value"); + credentials.setContext(context); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateCredentials_invalidContextType() throws Exception { + Credentials credentials = new Credentials(); + credentials.setToken("some-token"); + Field contextField = credentials.getClass().getSuperclass().getDeclaredField("context"); + contextField.setAccessible(true); + contextField.set(credentials, Integer.valueOf(5)); + try { + Validations.validateCredentials(credentials); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + // ── validateVaultConfiguration ──────────────────────────────────────────── @Test @@ -448,6 +557,16 @@ public void testValidateVaultConfiguration_delegatesToCredentialValidation() { // ── validateInsertRequest ───────────────────────────────────────────────── + @Test + public void testValidateInsertRequest_nullRequest() { + try { + Validations.validateInsertRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + @Test public void testValidateInsertRequest_nullRecords() { InsertRequest request = InsertRequest.builder().table("table1").records(null).build(); @@ -531,6 +650,24 @@ public void testValidateInsertRequest_upsertAtRecordLevelWhenTableAtRequestLevel } } + @Test + public void testValidateInsertRequest_upsertAtRequestLevelWhenNoTableAtRequestLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(InsertRecord.builder().table("table1").data(data).build()); + InsertRequest request = InsertRequest.builder() + .records(records) + .upsert(Collections.singletonList("email")) + .build(); + try { + Validations.validateInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + @Test public void testValidateInsertRequest_emptyUpsertAtRequestLevel() { Map data = new HashMap<>(); @@ -739,6 +876,16 @@ public void testValidateDetokenizeRequest_validRequestWithTokenGroupRedactions() // ── validateBulkInsertRequest ────────────────────────────────────────────── + @Test + public void testValidateBulkInsertRequest_nullRequest() { + try { + Validations.validateBulkInsertRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + @Test public void testValidateBulkInsertRequest_nullRecords() { BulkInsertRequest request = BulkInsertRequest.builder().records(null).build(); @@ -804,6 +951,42 @@ public void testValidateBulkInsertRequest_tableNotSpecifiedAnywhere() { } } + @Test + public void testValidateBulkInsertRequest_upsertAtRecordLevelWhenTableAtRequestLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().data(data).upsert(Collections.singletonList("email")).build()); + BulkInsertRequest request = BulkInsertRequest.builder() + .table("table1") + .records(records) + .build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateBulkInsertRequest_upsertAtRequestLevelWhenNoTableAtRequestLevel() { + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder() + .records(records) + .upsert(Collections.singletonList("email")) + .build(); + try { + Validations.validateBulkInsertRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + @Test public void testValidateBulkInsertRequest_emptyKeyInData() { Map data = new HashMap<>(); @@ -1121,4 +1304,339 @@ public void testValidateBulkTokenizeRequest_validRequestWithoutTokenGroupNames() Assert.fail(INVALID_EXCEPTION_THROWN); } } + + // ── validateQueryRequest ─────────────────────────────────────────────────── + + @Test + public void testValidateQueryRequest_nullQuery() { + com.skyflow.vault.data.QueryRequest request = com.skyflow.vault.data.QueryRequest.builder().build(); + try { + Validations.validateQueryRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateQueryRequest_emptyQuery() { + com.skyflow.vault.data.QueryRequest request = com.skyflow.vault.data.QueryRequest.builder().query(" ").build(); + try { + Validations.validateQueryRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateQueryRequest_validRequest() { + com.skyflow.vault.data.QueryRequest request = com.skyflow.vault.data.QueryRequest.builder() + .query("SELECT * FROM table1") + .build(); + try { + Validations.validateQueryRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateGetRequest ───────────────────────────────────────────────────── + + @Test + public void testValidateGetRequest_nullTable() { + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_emptyTable() { + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table(" ") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_emptyIds() { + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>()) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_nullIdInIds() { + ArrayList ids = new ArrayList<>(); + ids.add(null); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(ids) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_neitherIdsNorUniqueValues() { + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_bothIdsAndUniqueValues() { + Map uniqueValue = new HashMap<>(); + uniqueValue.put("email", "john@example.com"); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .uniqueValues(Collections.singletonList(uniqueValue)) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_emptyUniqueValues() { + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .uniqueValues(new ArrayList<>()) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_nullUniqueValueInUniqueValues() { + List> uniqueValues = new ArrayList<>(); + uniqueValues.add(null); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .uniqueValues(uniqueValues) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_emptyFields() { + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .fields(new ArrayList<>()) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_nullColumnRedactionObject() { + List columnRedactions = new ArrayList<>(); + columnRedactions.add(null); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .columnRedactions(columnRedactions) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_nullColumnNameInColumnRedaction() { + com.skyflow.vault.data.ColumnRedaction redaction = com.skyflow.vault.data.ColumnRedaction.builder() + .redaction("MASKED") + .build(); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .columnRedactions(Collections.singletonList(redaction)) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_nullRedactionInColumnRedaction() { + com.skyflow.vault.data.ColumnRedaction redaction = com.skyflow.vault.data.ColumnRedaction.builder() + .columnName("email") + .build(); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .columnRedactions(Collections.singletonList(redaction)) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_validRequestWithIds() { + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .build(); + try { + Validations.validateGetRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateGetRequest_validRequestWithUniqueValuesAndColumnRedactions() { + Map uniqueValue = new HashMap<>(); + uniqueValue.put("email", "john@example.com"); + com.skyflow.vault.data.ColumnRedaction redaction = com.skyflow.vault.data.ColumnRedaction.builder() + .columnName("email") + .redaction("MASKED") + .build(); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .uniqueValues(Collections.singletonList(uniqueValue)) + .columnRedactions(Collections.singletonList(redaction)) + .build(); + try { + Validations.validateGetRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateGetRequest (multi-table records) ────────────────────────────── + + @Test + public void testValidateGetRequest_bothSingleTableFieldsAndRecordsPassed() { + com.skyflow.vault.data.GetRecordRequest record = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table2") + .ids(new ArrayList<>(Collections.singletonList("id2"))) + .build(); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .records(Collections.singletonList(record)) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_nullRecordInRecords() { + List records = new ArrayList<>(); + records.add(null); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .records(records) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_invalidRecordWithinRecords() { + // second record is missing both ids and uniqueValues + com.skyflow.vault.data.GetRecordRequest validRecord = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .build(); + com.skyflow.vault.data.GetRecordRequest invalidRecord = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table2") + .build(); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .records(java.util.Arrays.asList(validRecord, invalidRecord)) + .build(); + try { + Validations.validateGetRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testValidateGetRequest_validMultiTableRecords() { + com.skyflow.vault.data.GetRecordRequest record1 = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .build(); + Map uniqueValue = new HashMap<>(); + uniqueValue.put("email", "john@example.com"); + com.skyflow.vault.data.GetRecordRequest record2 = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table2") + .uniqueValues(Collections.singletonList(uniqueValue)) + .build(); + com.skyflow.vault.data.GetRequest request = com.skyflow.vault.data.GetRequest.builder() + .records(java.util.Arrays.asList(record1, record2)) + .build(); + try { + Validations.validateGetRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } } diff --git a/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java index e0af4549..2e3773cc 100644 --- a/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java @@ -13,13 +13,18 @@ import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; import com.skyflow.generated.rest.resources.flowservice.RawFlowserviceClient; +import com.skyflow.generated.rest.resources.records.RawRecordsClient; +import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.generated.rest.types.FlowTokenizeResponseObjectToken; import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.V1ExecuteQueryRecordResponse; +import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; import com.skyflow.generated.rest.types.V1FlowDetokenizeResponse; import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; import com.skyflow.generated.rest.types.V1FlowTokenizeResponseObject; +import com.skyflow.generated.rest.types.V1GetResponse; import com.skyflow.generated.rest.types.V1InsertResponse; import com.skyflow.generated.rest.types.V1RecordResponseObject; import com.skyflow.utils.Constants; @@ -36,13 +41,23 @@ import com.skyflow.vault.data.DeleteTokensRequest; import com.skyflow.vault.data.DeleteTokensResponse; import com.skyflow.vault.data.DetokenizeData; +import com.skyflow.vault.data.DetokenizeOptions; import com.skyflow.vault.data.DetokenizeRequest; import com.skyflow.vault.data.DetokenizeResponse; +import com.skyflow.vault.data.GetOptions; +import com.skyflow.vault.data.GetRequest; +import com.skyflow.vault.data.GetResponse; import com.skyflow.vault.data.InsertOptions; import com.skyflow.vault.data.InsertRecord; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertResponse; +import com.skyflow.vault.data.QueryOptions; +import com.skyflow.vault.data.QueryRequest; +import com.skyflow.vault.data.QueryResponse; import com.skyflow.vault.data.RequestInterceptor; +import com.skyflow.vault.data.Success; +import com.skyflow.vault.data.Token; +import com.skyflow.vault.data.TokenizeOptions; import com.skyflow.vault.data.TokenizeRecord; import com.skyflow.vault.data.TokenizeRequest; import com.skyflow.vault.data.TokenizeResponse; @@ -58,6 +73,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -102,6 +118,14 @@ private static RawFlowserviceClient mockRawFlowservice(ApiClient mockApi) { return mockRaw; } + private static RawRecordsClient mockRawRecords(ApiClient mockApi) { + RecordsClient mockRecords = Mockito.mock(RecordsClient.class); + RawRecordsClient mockRaw = Mockito.mock(RawRecordsClient.class); + when(mockApi.records()).thenReturn(mockRecords); + when(mockRecords.withRawResponse()).thenReturn(mockRaw); + return mockRaw; + } + // ── insert ──────────────────────────────────────────────────────────────── @Test @@ -822,4 +846,608 @@ public void testBulkTokenizeAsync_success() throws Exception { Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); Assert.assertEquals(1, response.getSuccess().size()); } + + // ── additional bulk API-error coverage ─────────────────────────────────── + // + // Note: unlike the singular insert/detokenize/tokenize/deleteTokens calls, the bulk* + // entry points recover a per-batch ApiClientApiException into the response's errors list + // (via Utils.handleBulkXxxBatchException, invoked from the CompletableFuture + // .exceptionally()/.handle() callbacks inside VaultController's *BatchFutures helpers) + // instead of letting a SkyflowException escape the call. That is a deliberate resilience + // design (a single failed batch shouldn't fail an entire bulk request), so these tests + // assert the errors-list outcome rather than a thrown exception. + + @Test + public void testBulkInsertAsync_apiErrorCapturedInErrors() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.insert(any(), any())) + .thenThrow(new ApiClientApiException("insert failed", 401, "unauthorized")); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + + BulkInsertResponse response = controller.bulkInsertAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertTrue(response.getSuccess().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals(401, response.getErrors().get(0).getCode()); + } + + @Test + public void testBulkDeleteTokens_apiErrorCapturedInErrors() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.deletetoken(any(), any())) + .thenThrow(new ApiClientApiException("delete failed", 404, "not found")); + + VaultController controller = createControllerWithMock(mockApi); + + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + BulkDeleteTokensResponse response = controller.bulkDeleteTokens(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertTrue(response.getSuccess().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals(404, response.getErrors().get(0).getCode()); + } + + @Test + public void testBulkDeleteTokensAsync_apiErrorCapturedInErrors() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.deletetoken(any(), any())) + .thenThrow(new ApiClientApiException("delete failed", 404, "not found")); + + VaultController controller = createControllerWithMock(mockApi); + + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + BulkDeleteTokensResponse response = controller.bulkDeleteTokensAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertTrue(response.getSuccess().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals(404, response.getErrors().get(0).getCode()); + } + + @Test + public void testBulkTokenize_apiErrorCapturedInErrors() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokenize(any(), any())) + .thenThrow(new ApiClientApiException("tokenize failed", 400, "bad request")); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(BulkTokenizeRecord.builder().value("value1").tokenGroupNames(Collections.singletonList("group1")).build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(records).build(); + + BulkTokenizeResponse response = controller.bulkTokenize(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertTrue(response.getSuccess().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals(400, response.getErrors().get(0).getCode()); + } + + @Test + public void testBulkTokenizeAsync_apiErrorCapturedInErrors() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokenize(any(), any())) + .thenThrow(new ApiClientApiException("tokenize failed", 400, "bad request")); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(BulkTokenizeRecord.builder().value("value1").tokenGroupNames(Collections.singletonList("group1")).build()); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(records).build(); + + BulkTokenizeResponse response = controller.bulkTokenizeAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertTrue(response.getSuccess().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals(400, response.getErrors().get(0).getCode()); + } + + @Test + public void testBulkDetokenizeAsync_apiErrorCapturedInErrors() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.detokenize(any(), any())) + .thenThrow(new ApiClientApiException("detokenize failed", 401, "unauthorized")); + + VaultController controller = createControllerWithMock(mockApi); + + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(Collections.singletonList("token1")) + .build(); + + BulkDetokenizeResponse response = controller.bulkDetokenizeAsync(request).get(5, TimeUnit.SECONDS); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertTrue(response.getSuccess().isEmpty()); + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals(401, response.getErrors().get(0).getCode()); + } + + // ── multi-batch aggregation / partial-batch failure ────────────────────── + + @Test + public void testBulkInsert_multiBatchAggregatesAcrossBatches() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokens1 = new HashMap<>(); + tokens1.put("name", "tok-batch1"); + V1RecordResponseObject record1 = V1RecordResponseObject.builder().skyflowId("sky-id-batch1").tokens(tokens1).build(); + V1InsertResponse body1 = V1InsertResponse.builder().records(Collections.singletonList(record1)).build(); + ApiClientHttpResponse httpResp1 = new ApiClientHttpResponse<>(body1, buildOkHttpResponse()); + + Map tokens2 = new HashMap<>(); + tokens2.put("name", "tok-batch2"); + V1RecordResponseObject record2 = V1RecordResponseObject.builder().skyflowId("sky-id-batch2").tokens(tokens2).build(); + V1InsertResponse body2 = V1InsertResponse.builder().records(Collections.singletonList(record2)).build(); + ApiClientHttpResponse httpResp2 = new ApiClientHttpResponse<>(body2, buildOkHttpResponse()); + + when(mockRaw.insert(any(), any())).thenReturn(httpResp1).thenReturn(httpResp2); + + VaultController controller = createControllerWithMock(mockApi); + + // Constants.INSERT_BATCH_SIZE defaults to 50, so 75 records forces exactly two batches + // (50 + 25) — processBulkInsertSync/insertBatchFutures must merge success/error lists + // collected from more than one CompletableFuture into a single BulkInsertResponse. + ArrayList records = new ArrayList<>(); + for (int i = 0; i < 75; i++) { + Map data = new HashMap<>(); + data.put("name", "john" + i); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + } + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + + BulkInsertResponse response = controller.bulkInsert(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Mockito.verify(mockRaw, Mockito.times(2)).insert(any(), any()); + Assert.assertTrue(response.getErrors().isEmpty()); + Assert.assertEquals(2, response.getSuccess().size()); + Assert.assertEquals(75, response.getSummary().getTotalRecords()); + Assert.assertEquals(2, response.getSummary().getTotalInserted()); + + Success batch1Success = response.getSuccess().stream() + .filter(s -> "sky-id-batch1".equals(s.getSkyflowId())).findFirst().orElse(null); + Success batch2Success = response.getSuccess().stream() + .filter(s -> "sky-id-batch2".equals(s.getSkyflowId())).findFirst().orElse(null); + Assert.assertNotNull(batch1Success); + Assert.assertNotNull(batch2Success); + // Index offsets prove the batch-number * batchSize aggregation math in + // Utils.formatBulkInsertResponse: batch 0 starts at index 0, batch 1 at index 50. + Assert.assertEquals(0, batch1Success.getIndex()); + Assert.assertEquals(50, batch2Success.getIndex()); + } + + @Test + public void testBulkInsert_partialBatchFailureKeepsBatch1SuccessAndBatch2Error() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokens1 = new HashMap<>(); + tokens1.put("name", "tok-batch1"); + V1RecordResponseObject record1 = V1RecordResponseObject.builder().skyflowId("sky-id-batch1").tokens(tokens1).build(); + V1InsertResponse body1 = V1InsertResponse.builder().records(Collections.singletonList(record1)).build(); + ApiClientHttpResponse httpResp1 = new ApiClientHttpResponse<>(body1, buildOkHttpResponse()); + + when(mockRaw.insert(any(), any())) + .thenReturn(httpResp1) + .thenThrow(new ApiClientApiException("insert failed", 500, "server error")); + + VaultController controller = createControllerWithMock(mockApi); + + // 51 records -> batch 1 has 50 records (succeeds), batch 2 has 1 record (fails). + ArrayList records = new ArrayList<>(); + for (int i = 0; i < 51; i++) { + Map data = new HashMap<>(); + data.put("name", "john" + i); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + } + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + + BulkInsertResponse response = controller.bulkInsert(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Mockito.verify(mockRaw, Mockito.times(2)).insert(any(), any()); + + Assert.assertEquals(1, response.getSuccess().size()); + Assert.assertEquals("sky-id-batch1", response.getSuccess().get(0).getSkyflowId()); + Assert.assertEquals(0, response.getSuccess().get(0).getIndex()); + + Assert.assertEquals(1, response.getErrors().size()); + Assert.assertEquals(50, response.getErrors().get(0).getIndex()); + Assert.assertEquals(500, response.getErrors().get(0).getCode()); + + Assert.assertEquals(51, response.getSummary().getTotalRecords()); + Assert.assertEquals(1, response.getSummary().getTotalInserted()); + Assert.assertEquals(1, response.getSummary().getTotalFailed()); + } + + // ── formatBulkInsertResponse: List token shape ────────────────────── + + @Test + public void testBulkInsert_successWithListOfMapsTokenShape() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map tokenEntry = new HashMap<>(); + tokenEntry.put("token", "tok-xyz"); + tokenEntry.put("tokenGroupName", "group1"); + List> tokenList = new ArrayList<>(); + tokenList.add(tokenEntry); + + Map tokens = new HashMap<>(); + tokens.put("field1", tokenList); + + V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); + V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.insert(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + ArrayList records = new ArrayList<>(); + records.add(BulkInsertRecord.builder().table("table1").data(data).build()); + BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); + + BulkInsertResponse response = controller.bulkInsert(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getSuccess().size()); + + Success success = response.getSuccess().get(0); + Assert.assertNotNull(success.getTokens()); + List field1Tokens = success.getTokens().get("field1"); + Assert.assertNotNull(field1Tokens); + Assert.assertEquals(1, field1Tokens.size()); + Assert.assertEquals("tok-xyz", field1Tokens.get(0).getToken()); + Assert.assertEquals("group1", field1Tokens.get(0).getTokenGroupName()); + } + + // ── detokenize/tokenize interceptor header wiring ───────────────────────── + + @Test + public void testDetokenize_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + .token("token1").value("secret-value").build(); + V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + .response(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList data = new ArrayList<>(); + data.add(new DetokenizeData("token1")); + DetokenizeRequest request = DetokenizeRequest.builder().detokenizeData(data).build(); + + RequestInterceptor interceptor = ctx -> ctx.addHeader(CustomHeaderKey.SkyflowAccountName, "acct-name"); + DetokenizeOptions options = DetokenizeOptions.builder().interceptor(interceptor).build(); + + controller.detokenize(request, options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw).detokenize(any(), captor.capture()); + Assert.assertEquals("acct-name", captor.getValue().getHeaders().get(CustomHeaderKey.SkyflowAccountName.toString())); + } + + @Test + public void testTokenize_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + FlowTokenizeResponseObjectToken token = FlowTokenizeResponseObjectToken.builder() + .tokenGroupName("group1").token("tok-abc").build(); + V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() + .value("value1").tokens(Collections.singletonList(token)).build(); + V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder() + .response(Collections.singletonList(responseObject)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokenize(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + ArrayList records = new ArrayList<>(); + records.add(TokenizeRecord.builder().value("value1").tokenGroupNames(Collections.singletonList("group1")).build()); + TokenizeRequest request = TokenizeRequest.builder().data(records).build(); + + RequestInterceptor interceptor = ctx -> ctx.addHeader(CustomHeaderKey.SkyflowAccountID, "acct-123"); + TokenizeOptions options = TokenizeOptions.builder().interceptor(interceptor).build(); + + controller.tokenize(request, options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw).tokenize(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SkyflowAccountID.toString())); + } + + // ── query ───────────────────────────────────────────────────────────────── + + @Test + public void testQuery_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawRecordsClient mockRaw = mockRawRecords(mockApi); + + Map data = new HashMap<>(); + data.put("skyflowId", "sky-id-1"); + data.put("name", "john"); + V1ExecuteQueryRecordResponse record = V1ExecuteQueryRecordResponse.builder().data(data).build(); + V1ExecuteQueryResponse body = V1ExecuteQueryResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.flowServiceExecuteQuery(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + QueryRequest request = QueryRequest.builder().query("SELECT * FROM table1").build(); + + QueryResponse response = controller.query(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getFields().size()); + Assert.assertEquals("sky-id-1", response.getFields().get(0).get("skyflowId")); + Assert.assertNull(response.getErrors()); + } + + @Test + public void testQuery_apiErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawRecordsClient mockRaw = mockRawRecords(mockApi); + when(mockRaw.flowServiceExecuteQuery(any(), any())) + .thenThrow(new ApiClientApiException("query failed", 401, "unauthorized")); + + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().query("SELECT * FROM table1").build(); + + try { + controller.query(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(401, e.getHttpCode()); + } + } + + @Test + public void testQuery_networkErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawRecordsClient mockRaw = mockRawRecords(mockApi); + when(mockRaw.flowServiceExecuteQuery(any(), any())) + .thenThrow(new ApiClientException("Network error executing HTTP request")); + + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().query("SELECT * FROM table1").build(); + + try { + controller.query(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testQuery_emptyQueryThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().build(); + try { + controller.query(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testQuery_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawRecordsClient mockRaw = mockRawRecords(mockApi); + + Map data = new HashMap<>(); + data.put("skyflowId", "sky-id-1"); + V1ExecuteQueryRecordResponse record = V1ExecuteQueryRecordResponse.builder().data(data).build(); + V1ExecuteQueryResponse body = V1ExecuteQueryResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.flowServiceExecuteQuery(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().query("SELECT * FROM table1").build(); + + RequestInterceptor interceptor = ctx -> ctx.addHeader(CustomHeaderKey.SkyflowAccountID, "acct-123"); + QueryOptions options = QueryOptions.builder().interceptor(interceptor).build(); + + controller.query(request, options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw).flowServiceExecuteQuery(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SkyflowAccountID.toString())); + } + + // ── get ─────────────────────────────────────────────────────────────────── + + @Test + public void testGet_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").data(data).build(); + V1GetResponse body = V1GetResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.get(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + GetRequest request = GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("sky-id-1"))) + .build(); + + GetResponse response = controller.get(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getData().size()); + Assert.assertEquals("sky-id-1", response.getData().get(0).get("skyflowId")); + Assert.assertEquals("john", response.getData().get(0).get("name")); + Assert.assertTrue(response.getErrors().isEmpty()); + } + + @Test + public void testGet_apiErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.get(any(), any())) + .thenThrow(new ApiClientApiException("get failed", 401, "unauthorized")); + + VaultController controller = createControllerWithMock(mockApi); + GetRequest request = GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("sky-id-1"))) + .build(); + + try { + controller.get(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(401, e.getHttpCode()); + } + } + + @Test + public void testGet_networkErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.get(any(), any())) + .thenThrow(new ApiClientException("Network error executing HTTP request")); + + VaultController controller = createControllerWithMock(mockApi); + GetRequest request = GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("sky-id-1"))) + .build(); + + try { + controller.get(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testGet_invalidRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + GetRequest request = GetRequest.builder().table("table1").build(); + try { + controller.get(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } + + @Test + public void testGet_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map data = new HashMap<>(); + data.put("name", "john"); + V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").data(data).build(); + V1GetResponse body = V1GetResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.get(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + GetRequest request = GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("sky-id-1"))) + .build(); + + RequestInterceptor interceptor = ctx -> ctx.addHeader(CustomHeaderKey.SkyflowAccountID, "acct-123"); + GetOptions options = GetOptions.builder().interceptor(interceptor).build(); + + controller.get(request, options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw).get(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SkyflowAccountID.toString())); + } + + @Test + public void testGet_multiTableRecordsSuccess() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + + Map data1 = new HashMap<>(); + data1.put("name", "john"); + V1RecordResponseObject record1 = V1RecordResponseObject.builder() + .skyflowId("sky-id-1").tableName("table1").data(data1).build(); + Map data2 = new HashMap<>(); + data2.put("email", "jane@example.com"); + V1RecordResponseObject record2 = V1RecordResponseObject.builder() + .skyflowId("sky-id-2").tableName("table2").data(data2).build(); + V1GetResponse body = V1GetResponse.builder().records(java.util.Arrays.asList(record1, record2)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.get(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + + com.skyflow.vault.data.GetRecordRequest recordRequest1 = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("sky-id-1"))) + .build(); + com.skyflow.vault.data.GetRecordRequest recordRequest2 = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table2") + .ids(new ArrayList<>(Collections.singletonList("sky-id-2"))) + .build(); + GetRequest request = GetRequest.builder() + .records(java.util.Arrays.asList(recordRequest1, recordRequest2)) + .build(); + + GetResponse response = controller.get(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(2, response.getData().size()); + Assert.assertEquals("table1", response.getData().get(0).get("tableName")); + Assert.assertEquals("table2", response.getData().get(1).get("tableName")); + } + + @Test + public void testGet_bothTableAndRecordsThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + + com.skyflow.vault.data.GetRecordRequest recordRequest = com.skyflow.vault.data.GetRecordRequest.builder() + .table("table2") + .ids(new ArrayList<>(Collections.singletonList("id2"))) + .build(); + GetRequest request = GetRequest.builder() + .table("table1") + .ids(new ArrayList<>(Collections.singletonList("id1"))) + .records(Collections.singletonList(recordRequest)) + .build(); + + try { + controller.get(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + } } diff --git a/flowvault/src/test/java/com/skyflow/vault/data/BulkResponseTests.java b/flowvault/src/test/java/com/skyflow/vault/data/BulkResponseTests.java new file mode 100644 index 00000000..ead482b1 --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/vault/data/BulkResponseTests.java @@ -0,0 +1,225 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Tests for the Bulk*Response classes: {@link BulkInsertResponse}, {@link BulkDetokenizeResponse}, + * {@link BulkDeleteTokensResponse} and {@link BulkTokenizeResponse}. + * + *

Each has a 2-arg constructor (success/errors only, summary and originalPayload-derived + * fields stay null) and a 3-arg constructor (adds originalPayload and computes a summary). + * BulkInsertResponse/BulkDetokenizeResponse additionally derive a retry list from the + * originalPayload, filtering on a "5xx except 529" retryable-status rule. + */ +public class BulkResponseTests { + + // ── BulkInsertResponse ─────────────────────────────────────────────────── + + @Test + public void testBulkInsertResponse_twoArgConstructorLeavesSummaryAndRetryDependenciesNull() { + List success = Collections.emptyList(); + List errors = Collections.emptyList(); + + BulkInsertResponse response = new BulkInsertResponse(success, errors); + + Assert.assertNull(response.getSummary()); + Assert.assertEquals(success, response.getSuccess()); + Assert.assertEquals(errors, response.getErrors()); + // No errors, so the retry list is empty and originalPayload (null) is never dereferenced. + Assert.assertTrue(response.getRecordsToRetry().isEmpty()); + } + + @Test + public void testBulkInsertResponse_threeArgConstructorComputesSummary() { + List success = Collections.singletonList( + new Success(0, "id-1", null, null, "table1")); + List errors = Collections.singletonList( + new ErrorRecord(1, "failed", 400)); + ArrayList originalPayload = new ArrayList<>(Arrays.asList( + BulkInsertRecord.builder().table("table1").build(), + BulkInsertRecord.builder().table("table1").build())); + + BulkInsertResponse response = new BulkInsertResponse(success, errors, originalPayload); + + Assert.assertNotNull(response.getSummary()); + Assert.assertEquals(2, response.getSummary().getTotalRecords()); + Assert.assertEquals(1, response.getSummary().getTotalInserted()); + Assert.assertEquals(1, response.getSummary().getTotalFailed()); + } + + @Test + public void testBulkInsertResponse_getRecordsToRetryFiltersRetryableStatusCodesOnly() { + BulkInsertRecord record0 = BulkInsertRecord.builder().table("t0").build(); + BulkInsertRecord record1 = BulkInsertRecord.builder().table("t1").build(); + BulkInsertRecord record2 = BulkInsertRecord.builder().table("t2").build(); + BulkInsertRecord record3 = BulkInsertRecord.builder().table("t3").build(); + ArrayList originalPayload = new ArrayList<>( + Arrays.asList(record0, record1, record2, record3)); + + List errors = Arrays.asList( + new ErrorRecord(0, "server error", 500), // retryable (lower bound) + new ErrorRecord(1, "bad request", 400), // not retryable + new ErrorRecord(2, "server error", 599), // retryable (upper bound) + new ErrorRecord(3, "special case", 529)); // explicitly excluded + + BulkInsertResponse response = new BulkInsertResponse( + Collections.emptyList(), errors, originalPayload); + + ArrayList recordsToRetry = response.getRecordsToRetry(); + + Assert.assertEquals(2, recordsToRetry.size()); + Assert.assertTrue(recordsToRetry.contains(record0)); + Assert.assertTrue(recordsToRetry.contains(record2)); + Assert.assertFalse(recordsToRetry.contains(record1)); + Assert.assertFalse(recordsToRetry.contains(record3)); + } + + @Test + public void testBulkInsertResponse_toStringNotNull() { + BulkInsertResponse response = new BulkInsertResponse(Collections.emptyList(), Collections.emptyList()); + Assert.assertNotNull(response.toString()); + } + + // ── BulkDetokenizeResponse ─────────────────────────────────────────────── + + @Test + public void testBulkDetokenizeResponse_twoArgConstructorLeavesSummaryNull() { + List success = Collections.emptyList(); + List errors = Collections.emptyList(); + + BulkDetokenizeResponse response = new BulkDetokenizeResponse(success, errors); + + Assert.assertNull(response.getSummary()); + Assert.assertEquals(success, response.getSuccess()); + Assert.assertEquals(errors, response.getErrors()); + Assert.assertTrue(response.getTokensToRetry().isEmpty()); + } + + @Test + public void testBulkDetokenizeResponse_threeArgConstructorComputesSummary() { + List success = Collections.singletonList( + new DetokenizeResponseObject(0, "tok-1", "value", "group1", null, null)); + List errors = Collections.singletonList(new ErrorRecord(1, "failed", 404)); + List originalPayload = Arrays.asList("tok-1", "tok-2"); + + BulkDetokenizeResponse response = new BulkDetokenizeResponse(success, errors, originalPayload); + + Assert.assertNotNull(response.getSummary()); + Assert.assertEquals(2, response.getSummary().getTotalTokens()); + Assert.assertEquals(1, response.getSummary().getTotalDetokenized()); + Assert.assertEquals(1, response.getSummary().getTotalFailed()); + } + + @Test + public void testBulkDetokenizeResponse_getTokensToRetryFiltersRetryableStatusCodesOnly() { + List originalPayload = Arrays.asList("tok-0", "tok-1", "tok-2", "tok-3"); + List errors = Arrays.asList( + new ErrorRecord(0, "server error", 500), + new ErrorRecord(1, "bad request", 400), + new ErrorRecord(2, "server error", 599), + new ErrorRecord(3, "special case", 529)); + + BulkDetokenizeResponse response = new BulkDetokenizeResponse( + Collections.emptyList(), errors, originalPayload); + + List tokensToRetry = response.getTokensToRetry(); + + Assert.assertEquals(2, tokensToRetry.size()); + Assert.assertTrue(tokensToRetry.contains("tok-0")); + Assert.assertTrue(tokensToRetry.contains("tok-2")); + Assert.assertFalse(tokensToRetry.contains("tok-1")); + Assert.assertFalse(tokensToRetry.contains("tok-3")); + } + + @Test + public void testBulkDetokenizeResponse_toStringNotNull() { + BulkDetokenizeResponse response = new BulkDetokenizeResponse(Collections.emptyList(), Collections.emptyList()); + Assert.assertNotNull(response.toString()); + } + + // ── BulkDeleteTokensResponse ───────────────────────────────────────────── + + @Test + public void testBulkDeleteTokensResponse_twoArgConstructorLeavesSummaryNull() { + List success = Collections.emptyList(); + List errors = Collections.emptyList(); + + BulkDeleteTokensResponse response = new BulkDeleteTokensResponse(success, errors); + + Assert.assertNull(response.getSummary()); + Assert.assertEquals(success, response.getSuccess()); + Assert.assertEquals(errors, response.getErrors()); + } + + @Test + public void testBulkDeleteTokensResponse_threeArgConstructorComputesSummary() { + List success = Collections.singletonList(new DeleteTokensSuccess(0, "tok-1")); + List errors = Collections.singletonList(new ErrorRecord(1, "failed", 404)); + List originalPayload = Arrays.asList("tok-1", "tok-2"); + + BulkDeleteTokensResponse response = new BulkDeleteTokensResponse(success, errors, originalPayload); + + Assert.assertNotNull(response.getSummary()); + Assert.assertEquals(2, response.getSummary().getTotalTokens()); + Assert.assertEquals(1, response.getSummary().getTotalDeleted()); + Assert.assertEquals(1, response.getSummary().getTotalFailed()); + } + + @Test + public void testBulkDeleteTokensResponse_toStringNotNull() { + BulkDeleteTokensResponse response = new BulkDeleteTokensResponse(Collections.emptyList(), Collections.emptyList()); + Assert.assertNotNull(response.toString()); + } + + // ── BulkTokenizeResponse ───────────────────────────────────────────────── + + @Test + public void testBulkTokenizeResponse_twoArgConstructorLeavesSummaryNull() { + List success = Collections.emptyList(); + List errors = Collections.emptyList(); + + BulkTokenizeResponse response = new BulkTokenizeResponse(success, errors); + + Assert.assertNull(response.getSummary()); + Assert.assertEquals(success, response.getSuccess()); + Assert.assertEquals(errors, response.getErrors()); + } + + @Test + public void testBulkTokenizeResponse_threeArgConstructorClassifiesEachIndex() { + // index 0: success only -> totalTokenized + // index 1: success AND error -> totalPartial + // index 2: error only -> totalFailed + List success = Arrays.asList( + new TokenizeSuccess(0, "v0"), + new TokenizeSuccess(1, "v1")); + List errors = Arrays.asList( + new ErrorRecord(1, "partial failure", 500), + new ErrorRecord(2, "full failure", 404)); + List originalPayload = Arrays.asList( + BulkTokenizeRecord.builder().value("v0").build(), + BulkTokenizeRecord.builder().value("v1").build(), + BulkTokenizeRecord.builder().value("v2").build()); + + BulkTokenizeResponse response = new BulkTokenizeResponse(success, errors, originalPayload); + + TokenizeSummary summary = response.getSummary(); + Assert.assertNotNull(summary); + Assert.assertEquals(3, summary.getTotalTokens()); + Assert.assertEquals(1, summary.getTotalTokenized()); + Assert.assertEquals(1, summary.getTotalPartial()); + Assert.assertEquals(1, summary.getTotalFailed()); + } + + @Test + public void testBulkTokenizeResponse_toStringNotNull() { + BulkTokenizeResponse response = new BulkTokenizeResponse(Collections.emptyList(), Collections.emptyList()); + Assert.assertNotNull(response.toString()); + } +} diff --git a/flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java b/flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java new file mode 100644 index 00000000..f88c7a39 --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java @@ -0,0 +1,71 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests for the single-field options/builder classes: {@link InsertOptions}, + * {@link DetokenizeOptions}, {@link TokenizeOptions} and {@link DeleteTokensOptions}. + * Each class simply wraps a {@link RequestInterceptor} with no validation. + */ +public class OptionsTests { + + private static final RequestInterceptor INTERCEPTOR = context -> { + }; + + // ── InsertOptions ──────────────────────────────────────────────────────── + + @Test + public void testInsertOptions_withInterceptor() { + InsertOptions options = InsertOptions.builder().interceptor(INTERCEPTOR).build(); + Assert.assertSame(INTERCEPTOR, options.getInterceptor()); + } + + @Test + public void testInsertOptions_withoutInterceptor() { + InsertOptions options = InsertOptions.builder().build(); + Assert.assertNull(options.getInterceptor()); + } + + // ── DetokenizeOptions ──────────────────────────────────────────────────── + + @Test + public void testDetokenizeOptions_withInterceptor() { + DetokenizeOptions options = DetokenizeOptions.builder().interceptor(INTERCEPTOR).build(); + Assert.assertSame(INTERCEPTOR, options.getInterceptor()); + } + + @Test + public void testDetokenizeOptions_withoutInterceptor() { + DetokenizeOptions options = DetokenizeOptions.builder().build(); + Assert.assertNull(options.getInterceptor()); + } + + // ── TokenizeOptions ────────────────────────────────────────────────────── + + @Test + public void testTokenizeOptions_withInterceptor() { + TokenizeOptions options = TokenizeOptions.builder().interceptor(INTERCEPTOR).build(); + Assert.assertSame(INTERCEPTOR, options.getInterceptor()); + } + + @Test + public void testTokenizeOptions_withoutInterceptor() { + TokenizeOptions options = TokenizeOptions.builder().build(); + Assert.assertNull(options.getInterceptor()); + } + + // ── DeleteTokensOptions ────────────────────────────────────────────────── + + @Test + public void testDeleteTokensOptions_withInterceptor() { + DeleteTokensOptions options = DeleteTokensOptions.builder().interceptor(INTERCEPTOR).build(); + Assert.assertSame(INTERCEPTOR, options.getInterceptor()); + } + + @Test + public void testDeleteTokensOptions_withoutInterceptor() { + DeleteTokensOptions options = DeleteTokensOptions.builder().build(); + Assert.assertNull(options.getInterceptor()); + } +} diff --git a/flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java b/flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java new file mode 100644 index 00000000..c51d88fd --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java @@ -0,0 +1,161 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.UpsertType; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Tests for the plain record/redaction data holders: {@link TokenGroupRedactions}, + * {@link BulkTokenGroupRedactions}, {@link InsertRecord}, {@link BulkInsertRecord}, + * {@link TokenizeRecord} and {@link BulkTokenizeRecord}. None of these classes perform + * validation in their builders, so coverage here is builder-construction plus getters. + */ +public class RecordAndRedactionTests { + + // ── TokenGroupRedactions ───────────────────────────────────────────────── + + @Test + public void testTokenGroupRedactions_gettersReturnBuilderValues() { + TokenGroupRedactions redaction = TokenGroupRedactions.builder() + .tokenGroupName("group1") + .redaction("MASK") + .build(); + + Assert.assertEquals("group1", redaction.getTokenGroupName()); + Assert.assertEquals("MASK", redaction.getRedaction()); + } + + @Test + public void testTokenGroupRedactions_defaultsAreNull() { + TokenGroupRedactions redaction = TokenGroupRedactions.builder().build(); + Assert.assertNull(redaction.getTokenGroupName()); + Assert.assertNull(redaction.getRedaction()); + } + + // ── BulkTokenGroupRedactions ───────────────────────────────────────────── + + @Test + public void testBulkTokenGroupRedactions_gettersReturnBuilderValues() { + BulkTokenGroupRedactions redaction = BulkTokenGroupRedactions.builder() + .tokenGroupName("group2") + .redaction("REDACT") + .build(); + + Assert.assertEquals("group2", redaction.getTokenGroupName()); + Assert.assertEquals("REDACT", redaction.getRedaction()); + } + + @Test + public void testBulkTokenGroupRedactions_defaultsAreNull() { + BulkTokenGroupRedactions redaction = BulkTokenGroupRedactions.builder().build(); + Assert.assertNull(redaction.getTokenGroupName()); + Assert.assertNull(redaction.getRedaction()); + } + + // ── InsertRecord ───────────────────────────────────────────────────────── + + @Test + public void testInsertRecord_gettersReturnBuilderValues() { + Map data = new HashMap<>(); + data.put("name", "John"); + List upsert = Arrays.asList("id"); + + InsertRecord record = InsertRecord.builder() + .table("persons") + .data(data) + .upsert(upsert) + .upsertType(UpsertType.UPDATE) + .build(); + + Assert.assertEquals("persons", record.getTable()); + Assert.assertEquals(data, record.getData()); + Assert.assertEquals(upsert, record.getUpsert()); + Assert.assertEquals(UpsertType.UPDATE, record.getUpsertType()); + } + + @Test + public void testInsertRecord_defaultsAreNull() { + InsertRecord record = InsertRecord.builder().build(); + Assert.assertNull(record.getTable()); + Assert.assertNull(record.getData()); + Assert.assertNull(record.getUpsert()); + Assert.assertNull(record.getUpsertType()); + } + + // ── BulkInsertRecord ───────────────────────────────────────────────────── + + @Test + public void testBulkInsertRecord_gettersReturnBuilderValues() { + Map data = new HashMap<>(); + data.put("name", "Jane"); + List upsert = Arrays.asList("id"); + + BulkInsertRecord record = BulkInsertRecord.builder() + .table("persons") + .data(data) + .upsert(upsert) + .upsertType(UpsertType.REPLACE) + .build(); + + Assert.assertEquals("persons", record.getTable()); + Assert.assertEquals(data, record.getData()); + Assert.assertEquals(upsert, record.getUpsert()); + Assert.assertEquals(UpsertType.REPLACE, record.getUpsertType()); + } + + @Test + public void testBulkInsertRecord_defaultsAreNull() { + BulkInsertRecord record = BulkInsertRecord.builder().build(); + Assert.assertNull(record.getTable()); + Assert.assertNull(record.getData()); + Assert.assertNull(record.getUpsert()); + Assert.assertNull(record.getUpsertType()); + } + + // ── TokenizeRecord ─────────────────────────────────────────────────────── + + @Test + public void testTokenizeRecord_gettersReturnBuilderValues() { + List groups = Arrays.asList("group1", "group2"); + TokenizeRecord record = TokenizeRecord.builder() + .value("secret-value") + .tokenGroupNames(groups) + .build(); + + Assert.assertEquals("secret-value", record.getValue()); + Assert.assertEquals(groups, record.getTokenGroupNames()); + } + + @Test + public void testTokenizeRecord_defaultsAreNull() { + TokenizeRecord record = TokenizeRecord.builder().build(); + Assert.assertNull(record.getValue()); + Assert.assertNull(record.getTokenGroupNames()); + } + + // ── BulkTokenizeRecord ─────────────────────────────────────────────────── + + @Test + public void testBulkTokenizeRecord_gettersReturnBuilderValues() { + List groups = Arrays.asList("group3"); + BulkTokenizeRecord record = BulkTokenizeRecord.builder() + .value(12345) + .tokenGroupNames(groups) + .build(); + + Assert.assertEquals(12345, record.getValue()); + Assert.assertEquals(groups, record.getTokenGroupNames()); + } + + @Test + public void testBulkTokenizeRecord_defaultsAreNull() { + BulkTokenizeRecord record = BulkTokenizeRecord.builder().build(); + Assert.assertNull(record.getValue()); + Assert.assertNull(record.getTokenGroupNames()); + } +} diff --git a/flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java b/flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java new file mode 100644 index 00000000..bdbbe6a8 --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java @@ -0,0 +1,303 @@ +package com.skyflow.vault.data; + +import com.skyflow.enums.UpsertType; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Tests for the simple request/response wrapper classes: {@link DeleteTokensRequest}, + * {@link InsertRequest}, {@link InsertResponse}, {@link TokenizeRequest}, {@link TokenizeResponse}, + * {@link DetokenizeRequest}, {@link DetokenizeResponse}, {@link DetokenizeRecordResponse}, + * {@link DetokenizeData}, {@link BulkDeleteTokensRequest}, {@link BulkDetokenizeRequest}, + * {@link BulkTokenizeRequest}, {@link BulkInsertRequest} and {@link DeleteTokensResponse}. + */ +public class RequestResponseWrapperTests { + + // ── DeleteTokensRequest ────────────────────────────────────────────────── + + @Test + public void testDeleteTokensRequest_getterReturnsBuilderValue() { + List tokens = Arrays.asList("tok-1", "tok-2"); + DeleteTokensRequest request = DeleteTokensRequest.builder().tokens(tokens).build(); + Assert.assertEquals(tokens, request.getTokens()); + } + + @Test + public void testDeleteTokensRequest_defaultIsNull() { + DeleteTokensRequest request = DeleteTokensRequest.builder().build(); + Assert.assertNull(request.getTokens()); + } + + // ── InsertRequest ──────────────────────────────────────────────────────── + + @Test + public void testInsertRequest_gettersReturnBuilderValues() { + ArrayList records = new ArrayList<>(Collections.singletonList( + InsertRecord.builder().table("persons").build())); + List upsert = Arrays.asList("id"); + + InsertRequest request = InsertRequest.builder() + .table("persons") + .upsert(upsert) + .upsertType(UpsertType.UPDATE) + .records(records) + .build(); + + Assert.assertEquals("persons", request.getTable()); + Assert.assertEquals(upsert, request.getUpsert()); + Assert.assertEquals(UpsertType.UPDATE, request.getUpsertType()); + Assert.assertEquals(records, request.getRecords()); + } + + @Test + public void testInsertRequest_defaultsAreNull() { + InsertRequest request = InsertRequest.builder().build(); + Assert.assertNull(request.getTable()); + Assert.assertNull(request.getUpsert()); + Assert.assertNull(request.getUpsertType()); + Assert.assertNull(request.getRecords()); + } + + // ── InsertResponse ─────────────────────────────────────────────────────── + + @Test + public void testInsertResponse_gettersReturnConstructorValues() { + ArrayList> insertedFields = new ArrayList<>(); + HashMap field = new HashMap<>(); + field.put("skyflow_id", "id-1"); + insertedFields.add(field); + ArrayList> errors = new ArrayList<>(); + + InsertResponse response = new InsertResponse(insertedFields, errors); + + Assert.assertEquals(insertedFields, response.getInsertedFields()); + Assert.assertEquals(errors, response.getErrors()); + } + + // ── TokenizeRequest ────────────────────────────────────────────────────── + + @Test + public void testTokenizeRequest_getterReturnsBuilderValue() { + ArrayList data = new ArrayList<>(Collections.singletonList( + TokenizeRecord.builder().value("v1").build())); + TokenizeRequest request = TokenizeRequest.builder().data(data).build(); + Assert.assertEquals(data, request.getData()); + } + + @Test + public void testTokenizeRequest_defaultIsNull() { + TokenizeRequest request = TokenizeRequest.builder().build(); + Assert.assertNull(request.getData()); + } + + // ── TokenizeResponse ───────────────────────────────────────────────────── + + @Test + public void testTokenizeResponse_defaultConstructorInitializesEmptyErrors() { + TokenizeResponse response = new TokenizeResponse(); + Assert.assertNotNull(response.getErrors()); + Assert.assertTrue(response.getErrors().isEmpty()); + Assert.assertNull(response.getTokenizedData()); + } + + @Test + public void testTokenizeResponse_errorsConstructorAndTokenizedDataSetter() { + ArrayList> errors = new ArrayList<>(); + HashMap error = new HashMap<>(); + error.put("error", "failed"); + errors.add(error); + + TokenizeResponse response = new TokenizeResponse(errors); + Assert.assertEquals(errors, response.getErrors()); + + List tokenizedData = Collections.singletonList(new TokenizeData("v1", 0)); + response.setTokenizedData(tokenizedData); + Assert.assertEquals(tokenizedData, response.getTokenizedData()); + } + + // ── DetokenizeRequest ──────────────────────────────────────────────────── + + @Test + public void testDetokenizeRequest_gettersReturnBuilderValues() { + ArrayList detokenizeData = new ArrayList<>(Collections.singletonList( + new DetokenizeData("tok-1"))); + List redactions = Collections.singletonList( + TokenGroupRedactions.builder().tokenGroupName("group1").redaction("MASK").build()); + + DetokenizeRequest request = DetokenizeRequest.builder() + .detokenizeData(detokenizeData) + .tokenGroupRedactions(redactions) + .build(); + + Assert.assertEquals(detokenizeData, request.getDetokenizeData()); + Assert.assertEquals(redactions, request.getTokenGroupRedactions()); + } + + @Test + public void testDetokenizeRequest_defaultsAreNull() { + DetokenizeRequest request = DetokenizeRequest.builder().build(); + Assert.assertNull(request.getDetokenizeData()); + Assert.assertNull(request.getTokenGroupRedactions()); + } + + // ── DetokenizeResponse ─────────────────────────────────────────────────── + + @Test + public void testDetokenizeResponse_gettersReturnConstructorValues() { + ArrayList detokenizedFields = new ArrayList<>(Collections.singletonList( + new DetokenizeRecordResponse("tok-1", "value", null, "group1", null))); + ArrayList errors = new ArrayList<>(); + + DetokenizeResponse response = new DetokenizeResponse(detokenizedFields, errors); + + Assert.assertEquals(detokenizedFields, response.getDetokenizedFields()); + Assert.assertEquals(errors, response.getErrors()); + Assert.assertNotNull(response.toString()); + } + + // ── DetokenizeRecordResponse ───────────────────────────────────────────── + + @Test + public void testDetokenizeRecordResponse_gettersReturnConstructorValues() { + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + DetokenizeRecordResponse response = new DetokenizeRecordResponse( + "tok-1", "plain-value", null, "group1", metadata); + + Assert.assertEquals("tok-1", response.getToken()); + Assert.assertEquals("plain-value", response.getValue()); + Assert.assertNull(response.getError()); + Assert.assertEquals("group1", response.getTokenGroupName()); + Assert.assertEquals(metadata, response.getMetadata()); + Assert.assertNotNull(response.toString()); + } + + @Test + public void testDetokenizeRecordResponse_errorCase() { + DetokenizeRecordResponse response = new DetokenizeRecordResponse( + "tok-2", null, "Token not found", null, null); + + Assert.assertEquals("tok-2", response.getToken()); + Assert.assertEquals("Token not found", response.getError()); + Assert.assertNull(response.getValue()); + Assert.assertNull(response.getTokenGroupName()); + Assert.assertNull(response.getMetadata()); + } + + // ── DetokenizeData ─────────────────────────────────────────────────────── + + @Test + public void testDetokenizeData_getterReturnsConstructorValue() { + DetokenizeData data = new DetokenizeData("tok-1"); + Assert.assertEquals("tok-1", data.getToken()); + } + + // ── BulkDeleteTokensRequest ────────────────────────────────────────────── + + @Test + public void testBulkDeleteTokensRequest_getterReturnsBuilderValue() { + List tokens = Arrays.asList("tok-1", "tok-2"); + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder().tokens(tokens).build(); + Assert.assertEquals(tokens, request.getTokens()); + } + + @Test + public void testBulkDeleteTokensRequest_defaultIsNull() { + BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder().build(); + Assert.assertNull(request.getTokens()); + } + + // ── BulkDetokenizeRequest ──────────────────────────────────────────────── + + @Test + public void testBulkDetokenizeRequest_gettersReturnBuilderValues() { + List tokens = Arrays.asList("tok-1", "tok-2"); + List redactions = Collections.singletonList( + BulkTokenGroupRedactions.builder().tokenGroupName("group1").redaction("MASK").build()); + + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder() + .tokens(tokens) + .tokenGroupRedactions(redactions) + .build(); + + Assert.assertEquals(tokens, request.getTokens()); + Assert.assertEquals(redactions, request.getTokenGroupRedactions()); + } + + @Test + public void testBulkDetokenizeRequest_defaultsAreNull() { + BulkDetokenizeRequest request = BulkDetokenizeRequest.builder().build(); + Assert.assertNull(request.getTokens()); + Assert.assertNull(request.getTokenGroupRedactions()); + } + + // ── BulkTokenizeRequest ────────────────────────────────────────────────── + + @Test + public void testBulkTokenizeRequest_getterReturnsBuilderValue() { + ArrayList data = new ArrayList<>(Collections.singletonList( + BulkTokenizeRecord.builder().value("v1").build())); + BulkTokenizeRequest request = BulkTokenizeRequest.builder().data(data).build(); + Assert.assertEquals(data, request.getData()); + } + + @Test + public void testBulkTokenizeRequest_defaultIsNull() { + BulkTokenizeRequest request = BulkTokenizeRequest.builder().build(); + Assert.assertNull(request.getData()); + } + + // ── BulkInsertRequest ──────────────────────────────────────────────────── + + @Test + public void testBulkInsertRequest_gettersReturnBuilderValues() { + ArrayList records = new ArrayList<>(Collections.singletonList( + BulkInsertRecord.builder().table("persons").build())); + List upsert = Arrays.asList("id"); + + BulkInsertRequest request = BulkInsertRequest.builder() + .table("persons") + .upsert(upsert) + .upsertType(UpsertType.REPLACE) + .records(records) + .build(); + + Assert.assertEquals("persons", request.getTable()); + Assert.assertEquals(upsert, request.getUpsert()); + Assert.assertEquals(UpsertType.REPLACE, request.getUpsertType()); + Assert.assertEquals(records, request.getRecords()); + } + + @Test + public void testBulkInsertRequest_defaultsAreNull() { + BulkInsertRequest request = BulkInsertRequest.builder().build(); + Assert.assertNull(request.getTable()); + Assert.assertNull(request.getUpsert()); + Assert.assertNull(request.getUpsertType()); + Assert.assertNull(request.getRecords()); + } + + // ── DeleteTokensResponse ───────────────────────────────────────────────── + + @Test + public void testDeleteTokensResponse_gettersReturnConstructorValues() { + List tokens = Arrays.asList("tok-1", "tok-2"); + ArrayList> errors = new ArrayList<>(); + HashMap error = new HashMap<>(); + error.put("error", "failed"); + errors.add(error); + + DeleteTokensResponse response = new DeleteTokensResponse(tokens, errors); + + Assert.assertEquals(tokens, response.getTokens()); + Assert.assertEquals(errors, response.getErrors()); + } +} diff --git a/flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java b/flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java new file mode 100644 index 00000000..22e38197 --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java @@ -0,0 +1,276 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Tests for the response/success/summary building-block classes that carry real + * constructor logic or toString() serialization: {@link Success}, {@link Summary}, + * {@link Token}, {@link TokenizeData}, {@link TokenizeSuccess}, {@link TokenizeSummary}, + * {@link DeleteTokensSuccess}, {@link DeleteTokensSummary}, {@link DetokenizeSummary}, + * {@link ErrorRecord} and {@link DetokenizeResponseObject}. + */ +public class ResponseComponentTests { + + // ── Success ────────────────────────────────────────────────────────────── + + @Test + public void testSuccess_gettersReturnConstructorValues() { + Map> tokens = new HashMap<>(); + tokens.put("group1", Collections.singletonList(new Token("tok-1", "group1"))); + Map data = new HashMap<>(); + data.put("name", "John"); + + Success success = new Success(2, "skyflow-id-1", tokens, data, "persons"); + + Assert.assertEquals(2, success.getIndex()); + Assert.assertEquals("skyflow-id-1", success.getSkyflowId()); + Assert.assertEquals(tokens, success.getTokens()); + Assert.assertEquals(data, success.getData()); + Assert.assertEquals("persons", success.getTable()); + } + + @Test + public void testSuccess_toStringContainsSkyflowId() { + Success success = new Success(0, "skyflow-id-2", new HashMap<>(), new HashMap<>(), "persons"); + String json = success.toString(); + Assert.assertNotNull(json); + Assert.assertTrue(json.contains("skyflow-id-2")); + } + + // ── Summary ────────────────────────────────────────────────────────────── + + @Test + public void testSummary_noArgConstructorDefaultsToZero() { + Summary summary = new Summary(); + Assert.assertEquals(0, summary.getTotalRecords()); + Assert.assertEquals(0, summary.getTotalInserted()); + Assert.assertEquals(0, summary.getTotalFailed()); + } + + @Test + public void testSummary_allArgConstructor() { + Summary summary = new Summary(10, 8, 2); + Assert.assertEquals(10, summary.getTotalRecords()); + Assert.assertEquals(8, summary.getTotalInserted()); + Assert.assertEquals(2, summary.getTotalFailed()); + } + + @Test + public void testSummary_toStringNotNull() { + Assert.assertNotNull(new Summary(1, 1, 0).toString()); + } + + // ── Token ──────────────────────────────────────────────────────────────── + + @Test + public void testToken_gettersReturnConstructorValues() { + Token token = new Token("tok-value", "group-name"); + Assert.assertEquals("tok-value", token.getToken()); + Assert.assertEquals("group-name", token.getTokenGroupName()); + } + + // ── TokenizeData ───────────────────────────────────────────────────────── + // Note: TokenizeData has an `index` field set in the constructor but exposes + // no getter for it - only getValue()/getTokens() are accessible. + + @Test + public void testTokenizeData_getValueAndEmptyTokensOnConstruction() { + TokenizeData data = new TokenizeData("plain-value", 0); + Assert.assertEquals("plain-value", data.getValue()); + Assert.assertNotNull(data.getTokens()); + Assert.assertTrue(data.getTokens().isEmpty()); + } + + @Test + public void testTokenizeData_addTokenPopulatesTokensMap() { + TokenizeData data = new TokenizeData("plain-value", 1); + data.addToken("group1", "tok-1"); + data.addToken("group2", "tok-2"); + + Map expected = new LinkedHashMap<>(); + expected.put("group1", "tok-1"); + expected.put("group2", "tok-2"); + Assert.assertEquals(expected, data.getTokens()); + } + + @Test + public void testTokenizeData_toStringNotNull() { + TokenizeData data = new TokenizeData("value", 0); + Assert.assertNotNull(data.toString()); + } + + // ── TokenizeSuccess ────────────────────────────────────────────────────── + + @Test + public void testTokenizeSuccess_getIndexAndValueAndEmptyTokensOnConstruction() { + TokenizeSuccess success = new TokenizeSuccess(3, "value-1"); + Assert.assertEquals(3, success.getIndex()); + Assert.assertEquals("value-1", success.getValue()); + Assert.assertNotNull(success.getTokens()); + Assert.assertTrue(success.getTokens().isEmpty()); + } + + @Test + public void testTokenizeSuccess_addTokenPopulatesTokensMap() { + TokenizeSuccess success = new TokenizeSuccess(0, "value-1"); + success.addToken("group1", "tok-1"); + Assert.assertEquals("tok-1", success.getTokens().get("group1")); + } + + @Test + public void testTokenizeSuccess_toStringNotNull() { + Assert.assertNotNull(new TokenizeSuccess(0, "value").toString()); + } + + // ── TokenizeSummary ────────────────────────────────────────────────────── + + @Test + public void testTokenizeSummary_noArgConstructorDefaultsToZero() { + TokenizeSummary summary = new TokenizeSummary(); + Assert.assertEquals(0, summary.getTotalTokens()); + Assert.assertEquals(0, summary.getTotalTokenized()); + Assert.assertEquals(0, summary.getTotalPartial()); + Assert.assertEquals(0, summary.getTotalFailed()); + } + + @Test + public void testTokenizeSummary_allArgConstructor() { + TokenizeSummary summary = new TokenizeSummary(10, 5, 3, 2); + Assert.assertEquals(10, summary.getTotalTokens()); + Assert.assertEquals(5, summary.getTotalTokenized()); + Assert.assertEquals(3, summary.getTotalPartial()); + Assert.assertEquals(2, summary.getTotalFailed()); + } + + @Test + public void testTokenizeSummary_toStringNotNull() { + Assert.assertNotNull(new TokenizeSummary(1, 1, 0, 0).toString()); + } + + // ── DeleteTokensSuccess ────────────────────────────────────────────────── + + @Test + public void testDeleteTokensSuccess_gettersReturnConstructorValues() { + DeleteTokensSuccess success = new DeleteTokensSuccess(1, "tok-1"); + Assert.assertEquals(1, success.getIndex()); + Assert.assertEquals("tok-1", success.getToken()); + } + + @Test + public void testDeleteTokensSuccess_toStringNotNull() { + Assert.assertNotNull(new DeleteTokensSuccess(0, "tok-1").toString()); + } + + // ── DeleteTokensSummary ────────────────────────────────────────────────── + + @Test + public void testDeleteTokensSummary_noArgConstructorDefaultsToZero() { + DeleteTokensSummary summary = new DeleteTokensSummary(); + Assert.assertEquals(0, summary.getTotalTokens()); + Assert.assertEquals(0, summary.getTotalDeleted()); + Assert.assertEquals(0, summary.getTotalFailed()); + } + + @Test + public void testDeleteTokensSummary_allArgConstructor() { + DeleteTokensSummary summary = new DeleteTokensSummary(5, 4, 1); + Assert.assertEquals(5, summary.getTotalTokens()); + Assert.assertEquals(4, summary.getTotalDeleted()); + Assert.assertEquals(1, summary.getTotalFailed()); + } + + @Test + public void testDeleteTokensSummary_toStringNotNull() { + Assert.assertNotNull(new DeleteTokensSummary(1, 1, 0).toString()); + } + + // ── DetokenizeSummary ──────────────────────────────────────────────────── + + @Test + public void testDetokenizeSummary_noArgConstructorDefaultsToZero() { + DetokenizeSummary summary = new DetokenizeSummary(); + Assert.assertEquals(0, summary.getTotalTokens()); + Assert.assertEquals(0, summary.getTotalDetokenized()); + Assert.assertEquals(0, summary.getTotalFailed()); + } + + @Test + public void testDetokenizeSummary_allArgConstructor() { + DetokenizeSummary summary = new DetokenizeSummary(6, 5, 1); + Assert.assertEquals(6, summary.getTotalTokens()); + Assert.assertEquals(5, summary.getTotalDetokenized()); + Assert.assertEquals(1, summary.getTotalFailed()); + } + + @Test + public void testDetokenizeSummary_toStringNotNull() { + Assert.assertNotNull(new DetokenizeSummary(1, 1, 0).toString()); + } + + // ── ErrorRecord ────────────────────────────────────────────────────────── + + @Test + public void testErrorRecord_threeArgConstructorLeavesRequestIdNull() { + ErrorRecord error = new ErrorRecord(0, "Not Found", 404); + Assert.assertEquals(0, error.getIndex()); + Assert.assertEquals("Not Found", error.getError()); + Assert.assertEquals(404, error.getCode()); + Assert.assertNull(error.getRequestId()); + } + + @Test + public void testErrorRecord_fourArgConstructorSetsRequestId() { + ErrorRecord error = new ErrorRecord(1, "Server Error", 500, "req-123"); + Assert.assertEquals(1, error.getIndex()); + Assert.assertEquals("Server Error", error.getError()); + Assert.assertEquals(500, error.getCode()); + Assert.assertEquals("req-123", error.getRequestId()); + } + + @Test + public void testErrorRecord_toStringNotNull() { + Assert.assertNotNull(new ErrorRecord(0, "err", 400).toString()); + } + + // ── DetokenizeResponseObject ───────────────────────────────────────────── + + @Test + public void testDetokenizeResponseObject_gettersReturnConstructorValues() { + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + DetokenizeResponseObject obj = new DetokenizeResponseObject( + 4, "tok-1", "plain-value", "group1", null, metadata); + + Assert.assertEquals(4, obj.getIndex()); + Assert.assertEquals("tok-1", obj.getToken()); + Assert.assertEquals("plain-value", obj.getValue()); + Assert.assertEquals("group1", obj.getTokenGroupName()); + Assert.assertNull(obj.getError()); + Assert.assertEquals(metadata, obj.getMetadata()); + } + + @Test + public void testDetokenizeResponseObject_errorCase() { + DetokenizeResponseObject obj = new DetokenizeResponseObject( + 0, "tok-2", null, null, "Token not found", null); + + Assert.assertEquals("Token not found", obj.getError()); + Assert.assertNull(obj.getValue()); + Assert.assertNull(obj.getTokenGroupName()); + Assert.assertNull(obj.getMetadata()); + } + + @Test + public void testDetokenizeResponseObject_toStringNotNull() { + DetokenizeResponseObject obj = new DetokenizeResponseObject(0, "tok", "v", "g", null, null); + Assert.assertNotNull(obj.toString()); + } +} diff --git a/v2/src/main/java/com/skyflow/vault/data/GetRequest.java b/v2/src/main/java/com/skyflow/vault/data/GetRequest.java index 0fccf7b8..edd9872e 100644 --- a/v2/src/main/java/com/skyflow/vault/data/GetRequest.java +++ b/v2/src/main/java/com/skyflow/vault/data/GetRequest.java @@ -7,10 +7,11 @@ import java.util.ArrayList; -public class GetRequest { +public class GetRequest extends BaseGetRequest { private final GetRequestBuilder builder; private GetRequest(GetRequestBuilder builder) { + super(builder); this.builder = builder; } @@ -18,14 +19,6 @@ public static GetRequestBuilder builder() { return new GetRequestBuilder(); } - public String getTable() { - return this.builder.table; - } - - public ArrayList getIds() { - return this.builder.ids; - } - public RedactionType getRedactionType() { return this.builder.redactionType; } @@ -34,10 +27,6 @@ public Boolean getReturnTokens() { return this.builder.returnTokens; } - public ArrayList getFields() { - return this.builder.fields; - } - public String getOffset() { return this.builder.offset; } @@ -71,12 +60,9 @@ public String getOrderBy() { return this.builder.orderBy; } - public static final class GetRequestBuilder { - private String table; - private ArrayList ids; + public static final class GetRequestBuilder extends BaseGetRequestBuilder { private RedactionType redactionType; private Boolean returnTokens; - private ArrayList fields; private String offset; private String limit; private Boolean downloadUrl; @@ -89,13 +75,21 @@ private GetRequestBuilder() { this.downloadUrl = true; } + @Override public GetRequestBuilder table(String table) { - this.table = table; + super.table(table); return this; } + @Override public GetRequestBuilder ids(ArrayList ids) { - this.ids = ids; + super.ids(ids); + return this; + } + + @Override + public GetRequestBuilder fields(ArrayList fields) { + super.fields(fields); return this; } @@ -109,11 +103,6 @@ public GetRequestBuilder returnTokens(Boolean returnTokens) { return this; } - public GetRequestBuilder fields(ArrayList fields) { - this.fields = fields; - return this; - } - public GetRequestBuilder offset(String offset) { this.offset = offset; return this; diff --git a/v2/src/main/java/com/skyflow/vault/data/GetResponse.java b/v2/src/main/java/com/skyflow/vault/data/GetResponse.java index 365fe38e..f9f082cd 100644 --- a/v2/src/main/java/com/skyflow/vault/data/GetResponse.java +++ b/v2/src/main/java/com/skyflow/vault/data/GetResponse.java @@ -1,38 +1,15 @@ package com.skyflow.vault.data; -import com.google.gson.Gson; - import java.util.ArrayList; import java.util.HashMap; -public class GetResponse { - private final ArrayList> data; - private final ArrayList> errors; - +/** + * Deprecation notice: the {@code skyflow_id} key in each {@link #getData()} record map is + * deprecated and will be removed in an upcoming release. Use {@code skyflowId} instead. + * Both keys are present simultaneously in v2 for backward compatibility. + */ +public class GetResponse extends BaseGetResponse { public GetResponse(ArrayList> data, ArrayList> errors) { - this.data = data; - this.errors = errors; - } - - /** - * Returns the list of record maps from the Get response. Each map contains all - * field name/value pairs for the record. - * - *

Deprecation notice: The {@code skyflow_id} key in each record map is - * deprecated and will be removed in an upcoming release. Use {@code skyflowId} instead. - * Both keys are present simultaneously in v2 for backward compatibility.

- */ - public ArrayList> getData() { - return data; - } - - public ArrayList> getErrors() { - return errors; - } - - @Override - public String toString() { - Gson gson = new Gson().newBuilder().serializeNulls().create(); - return gson.toJson(this); + super(data, errors); } } diff --git a/v2/src/main/java/com/skyflow/vault/data/QueryRequest.java b/v2/src/main/java/com/skyflow/vault/data/QueryRequest.java index 2aaa200d..ea27f5d1 100644 --- a/v2/src/main/java/com/skyflow/vault/data/QueryRequest.java +++ b/v2/src/main/java/com/skyflow/vault/data/QueryRequest.java @@ -1,28 +1,21 @@ package com.skyflow.vault.data; -public class QueryRequest { - private final QueryRequestBuilder builder; - +public class QueryRequest extends BaseQueryRequest { private QueryRequest(QueryRequestBuilder builder) { - this.builder = builder; + super(builder); } public static QueryRequestBuilder builder() { return new QueryRequestBuilder(); } - public String getQuery() { - return this.builder.query; - } - - public static final class QueryRequestBuilder { - private String query; - + public static final class QueryRequestBuilder extends BaseQueryRequestBuilder { private QueryRequestBuilder() { } + @Override public QueryRequestBuilder query(String query) { - this.query = query; + super.query(query); return this; } diff --git a/v2/src/main/java/com/skyflow/vault/data/QueryResponse.java b/v2/src/main/java/com/skyflow/vault/data/QueryResponse.java index afb32c60..4b51fc44 100644 --- a/v2/src/main/java/com/skyflow/vault/data/QueryResponse.java +++ b/v2/src/main/java/com/skyflow/vault/data/QueryResponse.java @@ -9,32 +9,14 @@ import java.util.ArrayList; import java.util.HashMap; -public class QueryResponse { - private final ArrayList> fields; - private final ArrayList> errors; - +/** + * Deprecation notice: the {@code skyflow_id} key in each {@link #getFields()} record map is + * deprecated and will be removed in an upcoming release. Use {@code skyflowId} instead. + * Both keys are present simultaneously in v2 for backward compatibility. + */ +public class QueryResponse extends BaseQueryResponse { public QueryResponse(ArrayList> fields) { - this.fields = fields; - this.errors = null; - } - - /** - * Returns the list of record maps from the Query response. Each map contains all - * field name/value pairs for the record. - * - *

Deprecation notice: The {@code skyflow_id} key in each record map is - * deprecated and will be removed in an upcoming release. Use {@code skyflowId} instead. - * Both keys are present simultaneously in v2 for backward compatibility.

- */ - public ArrayList> getFields() { - return fields; - } - - /** - * Always returns null. The Query API does not support partial-error responses. - */ - public ArrayList> getErrors() { - return errors; + super(fields); } @Override