From 47e0230d79ff4b87b3deb9004bf167f502f95351 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Fri, 26 Aug 2022 15:01:46 -0400 Subject: [PATCH 01/44] bump version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d89f1f22..142e7175 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.coveo push-api-client.java - 2.1.0 + 2.2.0 ${project.groupId}:${project.artifactId} jar Coveo Push API client. See more on https://github.com/coveo/push-api-client.java From 16229ddacc9c6c745c8fb5af5ea6bec8cdb3e981 Mon Sep 17 00:00:00 2001 From: Louis Bompart Date: Wed, 11 Jan 2023 16:53:35 -0500 Subject: [PATCH 02/44] chore: update CODEOWNERS (#23) --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 88b3a57c..dca7caca 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @olamothe @y-lakhdar @louis-bompart +* @coveo/dx From 9f6c8a344c213a26e11dccd84d90583db283846b Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Thu, 23 Mar 2023 15:46:52 -0400 Subject: [PATCH 03/44] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59f46e8f..4d0a54e0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Using Maven: com.coveo push-api-client.java - 1.0.0 + 2.2.0 ``` @@ -53,4 +53,4 @@ public class PushOneDocument { * cd into ./target * jar -cvf bundle.jar push-api-client.java-1.0.0-javadoc.jar push-api-client.java-1.0.0-javadoc.jar.asc push-api-client.java-1.0.0-sources.jar push-api-client.java-1.0.0-sources.jar.asc push-api-client.java-1.0.0.jar push-api-client.java-1.0.0.jar.asc push-api-client.java-1.0.0.pom push-api-client.java-1.0.0.pom.asc * Log into https://oss.sonatype.org/ -* Upload newly created bundle.jar \ No newline at end of file +* Upload newly created bundle.jar From f3889db255d00202dd1e209750a31b8f8f4ef7f7 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lachance Date: Fri, 21 Apr 2023 17:15:14 -0400 Subject: [PATCH 04/44] chore: create dependency-review.yml (#24) + Configure Dependency Review Dependency review helps you understand dependency changes and the security impact of these changes at every pull request. It provides an easily understandable visualization of dependency changes with a rich diff on the "Files Changed" tab of a pull request. The warning for .github/workflows/dependency-review.yml is expected. https://coveord.atlassian.net/browse/DEF-657 J:DEF-657 --- .github/workflows/dependency-review.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/dependency-review.yml diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..99203c22 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,17 @@ +name: 'Dependency Review' + +on: + pull_request: + branches: [ "main" ] + +permissions: + contents: read + pull-requests: write + +jobs: + dependency-Review: + name: Review + uses: coveo/public-actions/.github/workflows/dependency-review.yml@main + with: + public: true + distributed: true From 4731e1bcd32c4f85857766025d7064c5a9238729 Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 19 May 2023 14:02:45 -0400 Subject: [PATCH 05/44] ci: add codeql workflow (#26) * ci: add codeql workflow * remove unused option --- .github/workflows/codeql.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..dea2cef6 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,15 @@ +name: 'CodeQL' + +on: + push: + branches: ['main'] + + pull_request: + branches: ['main'] + + schedule: + - cron: '29 3 * * 6' # Runs at 03:29, only on Saturday. + +jobs: + analyze-java: + uses: coveo/actions/.github/workflows/java-maven-openjdk11-codeql.yml@main From 3a6b08a47a2c25802e43e21730530b3b5deed9f9 Mon Sep 17 00:00:00 2001 From: Yassine Date: Thu, 25 May 2023 08:42:24 -0400 Subject: [PATCH 06/44] feat: create `PushSource` and `catalogSource` classes (#30) https://coveord.atlassian.net/browse/LENS-839 --- .../java/com/coveo/pushapiclient/ApiUrl.java | 122 +++++++ .../com/coveo/pushapiclient/BaseSource.java | 32 ++ .../coveo/pushapiclient/CatalogSource.java | 154 +++++++++ .../pushapiclient/PushEnabledSource.java | 6 + .../com/coveo/pushapiclient/PushSource.java | 314 ++++++++++++++++++ .../java/com/coveo/pushapiclient/Source.java | 1 + .../pushapiclient/StreamEnabledSource.java | 6 + .../com/coveo/pushapiclient/ApiUrlTest.java | 87 +++++ 8 files changed, 722 insertions(+) create mode 100644 src/main/java/com/coveo/pushapiclient/ApiUrl.java create mode 100644 src/main/java/com/coveo/pushapiclient/BaseSource.java create mode 100644 src/main/java/com/coveo/pushapiclient/CatalogSource.java create mode 100644 src/main/java/com/coveo/pushapiclient/PushEnabledSource.java create mode 100644 src/main/java/com/coveo/pushapiclient/PushSource.java create mode 100644 src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java create mode 100644 src/test/java/com/coveo/pushapiclient/ApiUrlTest.java diff --git a/src/main/java/com/coveo/pushapiclient/ApiUrl.java b/src/main/java/com/coveo/pushapiclient/ApiUrl.java new file mode 100644 index 00000000..b416576d --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/ApiUrl.java @@ -0,0 +1,122 @@ +package com.coveo.pushapiclient; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Private util class to extract dynamic parts from a API URL + * Handles extraction of identifiers and platform URL from a source URL. + * + * @See https://docs.coveo.com/en/1546#push-api-url + * https://docs.coveo.com/en/3295#stream-api-url + */ +class ApiUrl { + private final String organizationId; + private final String sourceId; + private final PlatformUrl platformUrl; + private final String sourceUrl; + + public ApiUrl(URL sourceUrl) throws MalformedURLException { + List identifiers = this.extractIdentifiers(sourceUrl); + this.organizationId = identifiers.get(0); + this.sourceId = identifiers.get(1); + this.sourceUrl = sourceUrl.toString(); + this.platformUrl = this.extractPlatformUrl(sourceUrl); + } + + public ApiUrl(String organizationId, String sourceId, PlatformUrl platformUrl) { + this.organizationId = organizationId; + this.sourceId = sourceId; + this.platformUrl = platformUrl; + this.sourceUrl = String.format("https://api.cloud.coveo.com/push/v1/organizations/%s/sources/%s", + this.organizationId, this.sourceId); + } + + public String getUrl() { + return this.sourceUrl; + } + + public String getOrganizationId() { + return this.organizationId; + } + + public String getSourceId() { + return this.sourceId; + } + + public PlatformUrl getPlatformUrl() { + return this.platformUrl; + } + + private List extractIdentifiers(URL sourceUrl) throws MalformedURLException { + String host = sourceUrl.getPath(); + Pattern pattern = Pattern.compile("/push/v1/organizations/([^/]+)/sources/([^/]+)"); + Matcher matcher = pattern.matcher(host); + + if (matcher.find()) { + String organizationId = matcher.group(1); + String sourceId = matcher.group(2); + return Arrays.asList(organizationId, sourceId); + } + + String errorMessage = this + .getErrorMessage("Unable to find organization and source ids from the provided API url"); + throw new MalformedURLException(errorMessage); + } + + private PlatformUrl extractPlatformUrl(URL sourceUrl) throws MalformedURLException { + String host = sourceUrl.getHost(); + Pattern pattern = Pattern.compile("api([a-z]*)([a-z-]*)\\.cloud\\.coveo\\.com"); + Matcher matcher = pattern.matcher(host); + + if (matcher.find()) { + String extractedEnvironment = matcher.group(1); + String extractedRegion = matcher.group(2).replace("-", ""); + + Environment urlEnvironment = extractedEnvironment.isEmpty() + ? PlatformUrl.DEFAULT_ENVIRONMENT + : EnumSet.allOf(Environment.class) + .stream() + .filter(e -> e.getValue().equalsIgnoreCase(extractedEnvironment)) + .findFirst() + .orElseThrow(() -> new MalformedURLException( + String.format("Invalid platform environment '%s'", extractedEnvironment))); + + Region urlRegion = extractedRegion.isEmpty() + ? PlatformUrl.DEFAULT_REGION + : EnumSet.allOf(Region.class) + .stream() + .filter(r -> r.getValue().equalsIgnoreCase(extractedRegion)) + .findFirst() + .orElseThrow(() -> new MalformedURLException( + String.format("Invalid platform region '%s'", extractedRegion))); + + return new PlatformUrl(urlEnvironment, urlRegion); + + } + + String invalidHostMessage = this.getErrorMessage("Invalid API URL host"); + throw new MalformedURLException(invalidHostMessage); + } + + private String getErrorMessage(String reason) { + String newLine = System.getProperty("line.separator"); + String message = "The provided API URL is invalid"; + + message.concat(newLine).concat(reason); + + message + .concat(newLine) + .concat("For a Push Source, visit: https://docs.coveo.com/en/1546") + .concat(newLine) + .concat("For a Catalog Source, visit:https://docs.coveo.com/en/3295"); + + return message; + } + +} diff --git a/src/main/java/com/coveo/pushapiclient/BaseSource.java b/src/main/java/com/coveo/pushapiclient/BaseSource.java new file mode 100644 index 00000000..a3edd80c --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/BaseSource.java @@ -0,0 +1,32 @@ +package com.coveo.pushapiclient; + +public interface BaseSource { + /** + * Returns the API key used for all operations regarding your source. + * + * @return + */ + String getApiKey(); + + /** + * Returns the {@link PlatformUrl} object associated to the source. + * + * @return + */ + PlatformUrl getPlatformUrl(); + + /** + * The unique identifier of your organization. + * + * @return + */ + String getOrganizationId(); + + /** + * The unique identifier of your source. + * + * @return + */ + String getId(); + +} diff --git a/src/main/java/com/coveo/pushapiclient/CatalogSource.java b/src/main/java/com/coveo/pushapiclient/CatalogSource.java new file mode 100644 index 00000000..7fc9b08a --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/CatalogSource.java @@ -0,0 +1,154 @@ +package com.coveo.pushapiclient; + +import java.net.MalformedURLException; +import java.net.URL; + +// TODO: LENS-851 - Make public when ready +class CatalogSource implements StreamEnabledSource { + private final String apiKey; + private final ApiUrl urlExtractor; + + /** + * Create a Catalog source instance from its + * Stream API URL + * + * @param apiKey The API key used for all operations regarding your source. + *

+ * Ensure your API key has the required privileges for the + * operation you will be performing + * * + *

+ * For more information about which privileges are required, + * see + * Privilege + * Reference. + * + * @param sourceUrl The URL available when you edit your source in the Coveo + * Administration Console. The URL should contain your + * ORGANIZATION_ID and SOURCE_ID, + * which are required parameters for all operations regarding + * your source. + *

+ * Some examples of valid source URLs: + * + *

+     * https://api.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/stream/open
+     * https://api-eu.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/stream/open
+     *                  
+ * + * @throws MalformedURLException + */ + public CatalogSource(String apiKey, URL sourceUrl) throws MalformedURLException { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(sourceUrl); + } + + /** + * Create a Catalog source instance from its + * Stream API URL + * + * @param apiKey The API key used for all operations regarding your + * source. + *

+ * Ensure your API key has the required privileges for the + * operation you will be performing + * * + *

+ * For more information about which privileges are + * required, + * see + * Privilege + * Reference. + * + * @param organizationId The unique identifier of your organization. + *

+ * The Organization Id can be retrieved in the URL of your + * Coveo organization. + * + * @param sourceId The unique identifier of the target Catalog source. + *

+ * The Source Id can be retrieved when you edit your + * source in the Coveo + * Administration Console + * + */ + public static CatalogSource fromPlatformUrl(String apiKey, String organizationId, String sourceId) { + PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); + return new CatalogSource(apiKey, organizationId, sourceId, platformUrl); + } + + /** + * Create a Catalog source instance from its + * Stream API URL + * + * @param apiKey The API key used for all operations regarding your + * source. + *

+ * Ensure your API key has the required privileges for the + * operation you will be performing + * * + *

+ * For more information about which privileges are + * required, + * see + * Privilege + * Reference. + * + * @param organizationId The unique identifier of your organization. + *

+ * The Organization Id can be retrieved in the URL of your + * Coveo organization. + * + * @param sourceId The unique identifier of the target Catalog source. + *

+ * The Source Id can be retrieved when you edit your + * source in the Coveo + * Administration Console + * + * @param platformUrl The object containing additional information on the + * URL endpoint. + * You can use the {@link PlatformUrl} when your + * organization is located in a non-default Coveo + * environement and/or region. When not specified, the + * default platform URL values will be used: + * {@link PlatformUrl#DEFAULT_ENVIRONMENT} and + * {@link PlatformUrl#DEFAULT_REGION} + * + */ + public static CatalogSource fromPlatformUrl(String apiKey, String organizationId, String sourceId, + PlatformUrl platformUrl) { + return new CatalogSource(apiKey, organizationId, sourceId, platformUrl); + } + + private CatalogSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(organizationId, sourceId, platformUrl); + } + + @Override + public String getOrganizationId() { + return this.urlExtractor.getOrganizationId(); + } + + @Override + public PlatformUrl getPlatformUrl() { + return this.urlExtractor.getPlatformUrl(); + } + + @Override + public String getId() { + return this.urlExtractor.getSourceId(); + } + + @Override + public String getApiKey() { + return this.apiKey; + } + +} diff --git a/src/main/java/com/coveo/pushapiclient/PushEnabledSource.java b/src/main/java/com/coveo/pushapiclient/PushEnabledSource.java new file mode 100644 index 00000000..b90b5f1e --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/PushEnabledSource.java @@ -0,0 +1,6 @@ +package com.coveo.pushapiclient; + +// Marker Interface +public interface PushEnabledSource extends BaseSource { + +} diff --git a/src/main/java/com/coveo/pushapiclient/PushSource.java b/src/main/java/com/coveo/pushapiclient/PushSource.java new file mode 100644 index 00000000..4a17f9a5 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/PushSource.java @@ -0,0 +1,314 @@ +package com.coveo.pushapiclient; + +import com.google.gson.Gson; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.http.HttpResponse; + +// TODO: LENS-851 - Make public when ready +class PushSource implements PushEnabledSource { + private final String apiKey; + private final ApiUrl urlExtractor; + private final PlatformClient platformClient; + + @Override + public String getOrganizationId() { + return this.urlExtractor.getOrganizationId(); + } + + @Override + public PlatformUrl getPlatformUrl() { + return this.urlExtractor.getPlatformUrl(); + } + + @Override + public String getId() { + return this.urlExtractor.getSourceId(); + } + + @Override + public String getApiKey() { + return this.apiKey; + } + + /** + * Create a Push source instance from its + * Push API URL + * + * @param apiKey The API key used for all operations regarding your source. + *

+ * Ensure your API key has the required privileges for the + * operation you will be performing + * * + *

+ * For more information about which privileges are required, + * see + * Privilege + * Reference. + * + * @param sourceUrl The URL available when you edit your source in the Coveo + * Administration Console. The URL should contain your + * ORGANIZATION_ID and SOURCE_ID, + * which are required parameters for all operations regarding + * your source. + *

+ * Some examples of valid source URLs: + * + *

+     * https://api.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/documents
+     * https://api-eu.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/documents
+     *                  
+ * + * @throws MalformedURLException + */ + public PushSource(String apiKey, URL sourceUrl) throws MalformedURLException { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(sourceUrl); + String organizationId = urlExtractor.getOrganizationId(); + PlatformUrl platformUrl = urlExtractor.getPlatformUrl(); + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + } + + /** + * Create a Push source instance + * + * @param apiKey The API key used for all operations regarding your + * source. + *

+ * Ensure your API key has the required privileges for the + * operation you will be performing + * * + *

+ * For more information about which privileges are + * required, + * see + * Privilege + * Reference. + * + * @param organizationId The unique identifier of your organization. + *

+ * The Organization Id can be retrieved in the URL of your + * Coveo organization. + * + * @param sourceId The unique identifier of the target Push source. + *

+ * The Source Id can be retrieved when you edit your + * source in the Coveo + * Administration Console + * + */ + public static PushSource fromPlatformUrl(String apiKey, String organizationId, String sourceId) { + PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); + return new PushSource(apiKey, organizationId, sourceId, platformUrl); + } + + /** + * Create a Push source instance + * + * @param apiKey The API key used for all operations regarding your + * source. + *

+ * Ensure your API key has the required privileges for the + * operation you will be performing + * * + *

+ * For more information about which privileges are + * required, + * see + * Privilege + * Reference. + * + * @param organizationId The unique identifier of your organization. + *

+ * The Organization Id can be retrieved in the URL of your + * Coveo organization. + * + * @param sourceId The unique identifier of the target Push source. + *

+ * The Source Id can be retrieved when you edit your + * source in the Coveo + * Administration Console + * + * @param platformUrl The object containing additional information on the + * URL endpoint. + * You can use the {@link PlatformUrl} when your + * organization is located in a non-default Coveo + * environement and/or region. When not specified, the + * default platform URL values will be used: + * {@link PlatformUrl#DEFAULT_ENVIRONMENT} and + * {@link PlatformUrl#DEFAULT_REGION} + * + */ + public static PushSource fromPlatformUrl(String apiKey, String organizationId, String sourceId, + PlatformUrl platformUrl) { + return new PushSource(apiKey, organizationId, sourceId, platformUrl); + } + + private PushSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(organizationId, sourceId, platformUrl); + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + } + + /** + * Create or update a security identity. See [Adding a Single Security + * Identity](https://docs.coveo.com/en/167) and [Security Identity + * Models](https://docs.coveo.com/en/139). + * + * @param securityProviderId + * @param securityIdentityModel + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentity(String securityProviderId, + SecurityIdentityModel securityIdentityModel) throws IOException, InterruptedException { + return this.platformClient.createOrUpdateSecurityIdentity(securityProviderId, securityIdentityModel); + } + + /** + * Create or update a security identity alias. See [Adding a Single + * Alias](https://docs.coveo.com/en/142) and [User Alias Definition + * Examples](https://docs.coveo.com/en/46). + * + * @param securityProviderId + * @param securityIdentityAliasModel + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentityAlias(String securityProviderId, + SecurityIdentityAliasModel securityIdentityAliasModel) throws IOException, InterruptedException { + return this.platformClient.createOrUpdateSecurityIdentityAlias(securityProviderId, securityIdentityAliasModel); + } + + /** + * Delete a security identity. See [Disabling a Single Security + * Identity](https://docs.coveo.com/en/84). + * + * @param securityProviderId + * @param securityIdentityDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteSecurityIdentity(String securityProviderId, + SecurityIdentityDelete securityIdentityDelete) throws IOException, InterruptedException { + return this.platformClient.deleteSecurityIdentity(securityProviderId, securityIdentityDelete); + } + + /** + * Update the status of a Push source. See [Updating the Status of a Push + * Source](https://docs.coveo.com/en/35). + * + * @param status + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse updateSourceStatus(PushAPIStatus status) + throws IOException, InterruptedException { + return this.platformClient.updateSourceStatus(this.getId(), status); + } + + /** + * Delete old security identities. See [Disabling Old Security + * Identities](https://docs.coveo.com/en/33). + * + * @param securityProviderId + * @param batchDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteOldSecurityIdentities(String securityProviderId, + SecurityIdentityDeleteOptions batchDelete) throws IOException, InterruptedException { + return this.platformClient.deleteOldSecurityIdentities(securityProviderId, batchDelete); + } + + /** + * Manage batches of security identities. See [Manage Batches of Security + * Identities](https://docs.coveo.com/en/55). + * + * @param securityProviderId + * @param batchConfig + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse manageSecurityIdentities(String securityProviderId, + SecurityIdentityBatchConfig batchConfig) throws IOException, InterruptedException { + return this.platformClient.manageSecurityIdentities(securityProviderId, batchConfig); + } + + /** + * Manages pushing batches of Security Identities to a File Container, then into + * Coveo. See [Manage Batches of Security + * Identities](https://docs.coveo.com/en/55) + * + * @param securityProviderId + * @param batchIdentity + * @return + * @throws IOException + * @throws InterruptedException + */ + public SecurityIdentityBatchResponse batchUpdateSecurityIdentities(String securityProviderId, + BatchIdentity batchIdentity) throws IOException, InterruptedException { + SecurityIdentityBatchResponse securityIdentityBatchResponse = new SecurityIdentityBatchResponse(); + HttpResponse resFileContainer = this.platformClient.createFileContainer(); + FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); + String batchIdJson = new Gson().toJson(batchIdentity.marshal()); + securityIdentityBatchResponse.s3Response = this.platformClient.uploadContentToFileContainer(fileContainer, + batchIdJson); + if (securityIdentityBatchResponse.s3Response.statusCode() >= 200 + && securityIdentityBatchResponse.s3Response.statusCode() <= 299) { // maybe just 200 or 202 + SecurityIdentityBatchConfig batchConfig = new SecurityIdentityBatchConfig(fileContainer.fileId, 0l); + securityIdentityBatchResponse.batchResponse = this.manageSecurityIdentities(securityProviderId, + batchConfig); + } + return securityIdentityBatchResponse; + } + + /** + * Adds or updates an individual item in a push source. See [Adding a Single + * Item in a Push Source](https://docs.coveo.com/en/133). + * + * @param docBuilder + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse addOrUpdateDocument(DocumentBuilder docBuilder) + throws IOException, InterruptedException { + CompressionType compressionType = docBuilder.getDocument().compressedBinaryData != null + ? docBuilder.getDocument().compressedBinaryData.getCompressionType() + : CompressionType.UNCOMPRESSED; + return this.platformClient.pushDocument(this.getId(), docBuilder.marshal(), docBuilder.getDocument().uri, + compressionType); + } + + /** + * Deletes a specific item from a Push source. Optionally, the child items of + * that item can also be deleted. See [Deleting an Item in a Push + * Source](https://docs.coveo.com/en/171). + * + * @param documentId + * @param deleteChildren + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteDocument(String documentId, Boolean deleteChildren) + throws IOException, InterruptedException { + return this.platformClient.deleteDocument(this.getId(), documentId, deleteChildren); + } + +} diff --git a/src/main/java/com/coveo/pushapiclient/Source.java b/src/main/java/com/coveo/pushapiclient/Source.java index 3b09a562..2288d944 100644 --- a/src/main/java/com/coveo/pushapiclient/Source.java +++ b/src/main/java/com/coveo/pushapiclient/Source.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.net.http.HttpResponse; +// TODO: LENS-844 - Deprecate class public class Source { PlatformClient platformClient; diff --git a/src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java b/src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java new file mode 100644 index 00000000..b04912bf --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java @@ -0,0 +1,6 @@ +package com.coveo.pushapiclient; + +// Marker Interface +public interface StreamEnabledSource extends BaseSource { + +} diff --git a/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java b/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java new file mode 100644 index 00000000..964dcb55 --- /dev/null +++ b/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java @@ -0,0 +1,87 @@ +package com.coveo.pushapiclient; + +import static org.junit.Assert.assertEquals; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.junit.Test; + +public class ApiUrlTest { + + @Test + public void testSourceId() throws MalformedURLException { + ApiUrl url = new ApiUrl( + new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + assertEquals(url.getSourceId(), "my-source-id"); + } + + @Test + public void testOrganizationId() throws MalformedURLException { + ApiUrl url = new ApiUrl( + new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + assertEquals(url.getOrganizationId(), "my-org-id"); + } + + @Test + public void testPlatformUrl() throws MalformedURLException { + ApiUrl defaultUrl = new ApiUrl( + new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + ApiUrl regionOnlyUrl = new ApiUrl( + new URL("https://api-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + ApiUrl environmentOnlyUrl = new ApiUrl( + new URL("https://apidev.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + ApiUrl environmentAndRegionUrl = new ApiUrl( + new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + + assertEquals(defaultUrl.getPlatformUrl().getApiUrl(), "https://api.cloud.coveo.com"); + assertEquals(regionOnlyUrl.getPlatformUrl().getApiUrl(), "https://api-au.cloud.coveo.com"); + assertEquals(environmentOnlyUrl.getPlatformUrl().getApiUrl(), "https://apidev.cloud.coveo.com"); + assertEquals(environmentAndRegionUrl.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); + } + + @Test + public void testStreamApiUrl() throws MalformedURLException { + ApiUrl url = new ApiUrl( + new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/stream/open")); + + assertEquals(url.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); + assertEquals(url.getOrganizationId(), "my-org-id"); + assertEquals(url.getSourceId(), "my-source-id"); + } + + @Test(expected = MalformedURLException.class) + public void testInvalidEnvironmentUrl() throws MalformedURLException { + new ApiUrl( + new URL("https://apifoo.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + + } + @Test(expected = MalformedURLException.class) + public void testInvalidUrl() throws MalformedURLException { + new ApiUrl( + new URL("https://apifoo.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + + } + + @Test(expected = MalformedURLException.class) + public void testInvalidRegionUrl() throws MalformedURLException { + new ApiUrl( + new URL( + "https://api-bar.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + + } + + @Test(expected = MalformedURLException.class) + public void testInvalidPathUrl() throws MalformedURLException { + new ApiUrl( + new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/providers/provider-id/mappings")); + + } + + @Test(expected = MalformedURLException.class) + public void testInvalidHostUrl() throws MalformedURLException { + new ApiUrl( + new URL("https://platform.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + + } +} From d957202d18e3c5458c669018c760395deb64c0a0 Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 26 May 2023 08:29:44 -0400 Subject: [PATCH 07/44] chore: use CodeQL public action (#31) * chore: use codeql public action * ci: use mvn default arguments from workflow --- .github/workflows/codeql.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index dea2cef6..f69a22c6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,4 +12,6 @@ on: jobs: analyze-java: - uses: coveo/actions/.github/workflows/java-maven-openjdk11-codeql.yml@main + uses: coveo/public-actions/.github/workflows/java-maven-openjdk11-codeql.yml@main + with: + runs-on: "['linux', 'x64', 'ec2.instance-type = t3.large']" From 071ba147fbe500ef2d524e2ea692a1be1f0073dc Mon Sep 17 00:00:00 2001 From: Yassine Date: Wed, 31 May 2023 14:01:30 -0400 Subject: [PATCH 08/44] feat: implement `StreamService` class (#32) https://coveord.atlassian.net/browse/LENS-838 --- .github/workflows/build.yml | 4 +- .github/workflows/codeql.yml | 2 +- .../pushapiclient/DocumentUploadQueue.java | 21 ++++ .../coveo/pushapiclient/PlatformClient.java | 41 +++++++ .../coveo/pushapiclient/StreamResponse.java | 11 ++ .../coveo/pushapiclient/StreamService.java | 116 ++++++++++++++++++ .../pushapiclient/StreamServiceInternal.java | 52 ++++++++ .../coveo/pushapiclient/UploadStrategy.java | 9 ++ .../exceptions/NoOpenStreamException.java | 7 ++ .../pushapiclient/PlatformClientTest.java | 33 +++++ .../StreamServiceInternalTest.java | 96 +++++++++++++++ 11 files changed, 389 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java create mode 100644 src/main/java/com/coveo/pushapiclient/StreamResponse.java create mode 100644 src/main/java/com/coveo/pushapiclient/StreamService.java create mode 100644 src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java create mode 100644 src/main/java/com/coveo/pushapiclient/UploadStrategy.java create mode 100644 src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java create mode 100644 src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e3f75203..1768f2ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,10 +15,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 16 + - name: Set up JDK 11 uses: actions/setup-java@v2 with: - java-version: '16' + java-version: '11' distribution: 'adopt' - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f69a22c6..4b2d418e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -14,4 +14,4 @@ jobs: analyze-java: uses: coveo/public-actions/.github/workflows/java-maven-openjdk11-codeql.yml@main with: - runs-on: "['linux', 'x64', 'ec2.instance-type = t3.large']" + runs-on: ubuntu-latest diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java new file mode 100644 index 00000000..b21e0dd5 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -0,0 +1,21 @@ +package com.coveo.pushapiclient; + +import java.io.IOException; + +// TODO: LENS-851 - Make public +class DocumentUploadQueue { + private final UploadStrategy uploader; + + public DocumentUploadQueue(UploadStrategy uploader) { + this.uploader = uploader; + } + + public void flush() throws IOException, InterruptedException { + throw new UnsupportedOperationException("Unimplemented method (TODO: LENS-856)"); + } + + public void add(DocumentBuilder document) throws IOException, InterruptedException { + throw new UnsupportedOperationException("Unimplemented method (TODO: LENS-856)"); + } + +} diff --git a/src/main/java/com/coveo/pushapiclient/PlatformClient.java b/src/main/java/com/coveo/pushapiclient/PlatformClient.java index f54aca7b..7f0a1705 100644 --- a/src/main/java/com/coveo/pushapiclient/PlatformClient.java +++ b/src/main/java/com/coveo/pushapiclient/PlatformClient.java @@ -282,6 +282,47 @@ public HttpResponse deleteDocument(String sourceId, String documentId, B return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } + public HttpResponse openStream(String sourceId) throws IOException, InterruptedException { + String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + // TODO: LENS-875: standardize string manipulation + URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/stream/open", sourceId)); + + // TODO: LENS-876: reduce code duplication + HttpRequest request = HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + public HttpResponse closeStream(String sourceId, String streamId) throws IOException, InterruptedException { + String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/stream/%s/close", sourceId, streamId)); + + HttpRequest request = HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + public HttpResponse requireStreamChunk(String sourceId, String streamId) throws IOException, InterruptedException { + String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/stream/%s/chunk", sourceId, streamId)); + + HttpRequest request = HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + /** * Create a file container. See [Creating a File Container](https://docs.coveo.com/en/43). * diff --git a/src/main/java/com/coveo/pushapiclient/StreamResponse.java b/src/main/java/com/coveo/pushapiclient/StreamResponse.java new file mode 100644 index 00000000..61f2ceb7 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/StreamResponse.java @@ -0,0 +1,11 @@ +package com.coveo.pushapiclient; + +import java.util.Map; + +public class StreamResponse { + public String uploadUri; + public String fileId; + public String streamId; + public Map requiredHeaders; + +} diff --git a/src/main/java/com/coveo/pushapiclient/StreamService.java b/src/main/java/com/coveo/pushapiclient/StreamService.java new file mode 100644 index 00000000..b9212e20 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/StreamService.java @@ -0,0 +1,116 @@ +package com.coveo.pushapiclient; + +import java.io.IOException; +import java.net.http.HttpResponse; + +import com.coveo.pushapiclient.exceptions.NoOpenStreamException; +import com.google.gson.Gson; + +// TODO: LENS-851 - Make public +class StreamService { + private final StreamEnabledSource source; + private final PlatformClient platformClient; + private StreamServiceInternal service; + private String streamId; + private DocumentUploadQueue queue; + + /** + * Creates a service to stream your documents to the provided source by + * interacting with the Stream API. + * + *

+ * To perform full document + * updates, use the {@PushService}, since pushing documents with the + * {@StreamService} is equivalent to triggering a full source rebuild. The + * {@StreamService} can also be used for an initial catalog upload. + * + * @param source The source to which you want to send your documents. + */ + public StreamService(StreamEnabledSource source) { + String apiKey = source.getApiKey(); + String organizationId = source.getOrganizationId(); + PlatformUrl platformUrl = source.getPlatformUrl(); + UploadStrategy uploader = this.getUploadStrategy(); + + this.source = source; + this.queue = new DocumentUploadQueue(uploader); + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + this.service = new StreamServiceInternal(this.source, this.queue, this.platformClient); + } + + /** + * Adds documents to the previously specified source. + * This function will open a stream before uploading documents into it. + * + *

+ * If called several times, the service will automatically batch documents and + * create new stream chunks whenever the data payload exceeds the + * batch size limit + * set for the Stream API. + * + *

+ * Once there are no more documents to add, it is important to call the {@link StreamService#close} function + * in order to send any buffered documents and close the open stream. + * Otherwise, changes will not be reflected in the index. + * + *

+ *

+     * {@code
+     * //...
+     * StreamService service = new StreamService(source));
+     * for (DocumentBuilder document : fictionalDocumentList) {
+     *     service.add(document);
+     * }
+     * service.close(document);
+     * 
+ * + *

+ * For more code samples, visit Stream data to your catalog source + * + * @param document The documentBuilder to add to your source + * @throws InterruptedException + * @throws IOException + */ + public void add(DocumentBuilder document) throws IOException, InterruptedException { + this.service.add(document); + } + + /** + * Sends any buffered documents and closes the stream. + * + *

+ * Upon invoking this method, any indexed items not added through this {@link StreamService} instance will be removed. + * All documents added from the initialization of the service until the invocation of the {@link StreamService#close} function + * will completely replace the previous content of the source. + * + *

+ * When you upload a catalog into a source, it will replace the previous content + * of the source completely. Expect a 15-minute delay for the removal of the old + * items from the index. + * + * @return + * @throws IOException + * @throws InterruptedException + * @throws NoOpenStreamException + */ + public HttpResponse close() throws IOException, InterruptedException, NoOpenStreamException { + return this.service.close(); + } + + private UploadStrategy getUploadStrategy() { + return (batchUpdate) -> { + String sourceId = this.getSourceId(); + HttpResponse resFileContainer = this.platformClient.requireStreamChunk(sourceId, this.streamId); + FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); + String batchUpdateJson = new Gson().toJson(batchUpdate.marshal()); + return this.platformClient.uploadContentToFileContainer(fileContainer, + batchUpdateJson); + + }; + } + + private String getSourceId() { + return this.source.getId(); + } + +} diff --git a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java new file mode 100644 index 00000000..81f47c85 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java @@ -0,0 +1,52 @@ +package com.coveo.pushapiclient; + +import java.io.IOException; +import java.net.http.HttpResponse; + +import com.coveo.pushapiclient.exceptions.NoOpenStreamException; +import com.google.gson.Gson; + +/** + * For internal use only. Made to easily test the service without having to use PowerMock + */ +class StreamServiceInternal { + private final StreamEnabledSource source; + private final PlatformClient platformClient; + private String streamId; + private DocumentUploadQueue queue; + + public StreamServiceInternal(StreamEnabledSource source, DocumentUploadQueue queue, PlatformClient platformClient) { + this.source = source; + this.queue = queue; + this.platformClient = platformClient; + } + + public void add(DocumentBuilder document) throws IOException, InterruptedException { + if (this.streamId == null) { + this.streamId = this.getStreamId(); + } + queue.add(document); + } + + public HttpResponse close() throws IOException, InterruptedException, NoOpenStreamException { + if (this.streamId == null) { + throw new NoOpenStreamException( + "No open stream detected. A stream will automatically be opened once you start adding documents."); + } + queue.flush(); + String sourceId = this.getSourceId(); + return this.platformClient.closeStream(sourceId, this.streamId); + } + + private String getStreamId() throws IOException, InterruptedException { + String sourceId = this.getSourceId(); + HttpResponse response = this.platformClient.openStream(sourceId); + StreamResponse streamResponse = new Gson().fromJson(response.body(), StreamResponse.class); + return streamResponse.streamId; + } + + private String getSourceId() { + return this.source.getId(); + } + +} diff --git a/src/main/java/com/coveo/pushapiclient/UploadStrategy.java b/src/main/java/com/coveo/pushapiclient/UploadStrategy.java new file mode 100644 index 00000000..e77dd01c --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/UploadStrategy.java @@ -0,0 +1,9 @@ +package com.coveo.pushapiclient; + +import java.io.IOException; +import java.net.http.HttpResponse; + +@FunctionalInterface +public interface UploadStrategy { + HttpResponse apply(BatchUpdate batchUpdate) throws IOException, InterruptedException; +} diff --git a/src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java b/src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java new file mode 100644 index 00000000..91b2cf3a --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java @@ -0,0 +1,7 @@ +package com.coveo.pushapiclient.exceptions; + +public class NoOpenStreamException extends Exception { + public NoOpenStreamException(String errorMessage) { + super(errorMessage); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java b/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java index 8acf472b..b8b3d779 100644 --- a/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java +++ b/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java @@ -266,6 +266,39 @@ public void testPushFileContainerContent() throws IOException, InterruptedExcept assertAuthorizationHeader(); } + @Test + public void testOpenStream() throws IOException, InterruptedException { + client.openStream("my_source"); + verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/stream/open")); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } + + @Test + public void testRequireStreamChunk() throws IOException, InterruptedException { + client.requireStreamChunk("my_source", "stream_id"); + verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/stream/stream_id/chunk")); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } + + @Test + public void testCloseStream() throws IOException, InterruptedException { + client.closeStream("my_source", "stream_id"); + verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/stream/stream_id/close")); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } + @Test public void testDeleteDocument() throws IOException, InterruptedException { client.deleteDocument("my_source", document().uri, true); diff --git a/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java b/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java new file mode 100644 index 00000000..5779b240 --- /dev/null +++ b/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java @@ -0,0 +1,96 @@ +package com.coveo.pushapiclient; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.coveo.pushapiclient.exceptions.NoOpenStreamException; + +import java.io.IOException; +import java.net.http.HttpResponse; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class StreamServiceInternalTest { + @Mock + private StreamEnabledSource source; + + @Mock + private DocumentUploadQueue queue; + + @Mock + private PlatformClient platformClient; + + @InjectMocks + private StreamServiceInternal service; + + @Mock + private HttpResponse httpResponse; + + private AutoCloseable closeable; + private DocumentBuilder documentA; + private DocumentBuilder documentB; + + @Before + public void setUp() throws Exception { + documentA = new DocumentBuilder("https://my.document.uri?ref=1", "My first document title"); + documentB = new DocumentBuilder("https://my.document.uri?ref=2", "My second document title"); + + closeable = MockitoAnnotations.openMocks(this); + + when(httpResponse.body()).thenReturn("{\"streamId\": \"stream-id\"}"); + when(platformClient.openStream("my-source-id")).thenReturn(httpResponse); + when(source.getId()).thenReturn("my-source-id"); + } + + @After + public void closeService() throws Exception { + closeable.close(); + } + + @Test + public void testAddShouldOpenANewStream() throws IOException, InterruptedException { + service.add(documentA); + service.add(documentB); + + verify(this.platformClient, times(1)).openStream("my-source-id"); + } + + @Test + public void testAddShouldAddDocumentToQueue() throws IOException, InterruptedException { + service.add(documentA); + service.add(documentB); + + verify(queue, times(1)).add(documentA); + verify(queue, times(1)).add(documentB); + } + + @Test + public void testCloseShouldCloseOpenStream() throws IOException, InterruptedException, NoOpenStreamException { + service.add(documentA); + service.close(); + + verify(platformClient, times(1)).closeStream("my-source-id", "stream-id"); + } + + @Test + public void testCloseShouldFlushBufferedDocuments() + throws IOException, InterruptedException, NoOpenStreamException { + service.add(documentA); + service.close(); + + verify(queue, times(1)).flush(); + } + + @Test(expected = NoOpenStreamException.class) + public void givenNoOpenStream_whenClose_thenShouldThrow() + throws IOException, InterruptedException, NoOpenStreamException { + service.close(); + } + +} \ No newline at end of file From cd32e2e765ec4b9a89cdf7eb0406efdc0369dc97 Mon Sep 17 00:00:00 2001 From: Yassine Date: Thu, 1 Jun 2023 09:14:51 -0400 Subject: [PATCH 09/44] fix: provide JSON value (#36) --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4b2d418e..7e6e0e97 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -14,4 +14,4 @@ jobs: analyze-java: uses: coveo/public-actions/.github/workflows/java-maven-openjdk11-codeql.yml@main with: - runs-on: ubuntu-latest + runs-on: '"ubuntu-latest"' From cce3baf908a946eb3ce9d659a63e59572de86ad8 Mon Sep 17 00:00:00 2001 From: Yassine Date: Thu, 1 Jun 2023 13:02:32 -0400 Subject: [PATCH 10/44] feat: implement `DocumentUploadQueue` class (#33) https://coveord.atlassian.net/browse/LENS-856 --- .gitignore | 1 + .../pushapiclient/DocumentUploadQueue.java | 90 +++++++- .../DocumentUploadQueueTest.java | 192 ++++++++++++++++++ 3 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java diff --git a/.gitignore b/.gitignore index 0f802245..d5a7ca72 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ .env /.idea/ +.vscode \ No newline at end of file diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index b21e0dd5..79014137 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -1,21 +1,105 @@ package com.coveo.pushapiclient; import java.io.IOException; +import java.util.ArrayList; -// TODO: LENS-851 - Make public +/** + * Represents a queue for uploading documents using a specified upload strategy + */ class DocumentUploadQueue { private final UploadStrategy uploader; + private final int maxQueueSize = 5 * 1024 * 1024; + private ArrayList documentToAddList; + private ArrayList documentToDeleteList; + private int size; + /** + * Constructs a new DocumentUploadQueue object with a default maximum queue size + * limit of 5MB. + * + * @param uploader The upload strategy to be used for document uploads. + */ public DocumentUploadQueue(UploadStrategy uploader) { + this.documentToAddList = new ArrayList<>(); + this.documentToDeleteList = new ArrayList<>(); this.uploader = uploader; } + /** + * Flushes the accumulated documents by applying the upload strategy. + * + * @throws IOException If an I/O error occurs during the upload. + * @throws InterruptedException If the upload process is interrupted. + */ public void flush() throws IOException, InterruptedException { - throw new UnsupportedOperationException("Unimplemented method (TODO: LENS-856)"); + if (this.isEmpty()) { + return; + } + BatchUpdate batch = this.getBatch(); + // TODO: LENS-871: support concurrent requests + this.uploader.apply(batch); + this.size = 0; + this.documentToAddList.clear(); + this.documentToDeleteList.clear(); } + /** + * Adds a {@link DocumentBuilder} to the upload queue and flushes the queue if + * it exceeds the maximum content length. + * See {@link DocumentUploadQueue#flush}. + * + * @param document The document to be added to the index. + * @throws IOException If an I/O error occurs during the upload. + * @throws InterruptedException If the upload process is interrupted. + */ public void add(DocumentBuilder document) throws IOException, InterruptedException { - throw new UnsupportedOperationException("Unimplemented method (TODO: LENS-856)"); + if (document == null) { + return; + } + + final int sizeOfDoc = document.marshal().getBytes().length; + if (this.size + sizeOfDoc >= this.maxQueueSize) { + this.flush(); + } + if (document != null) { + documentToAddList.add(document); + this.size += sizeOfDoc; + } + } + + /** + * Adds a {@link DeleteDocument} to the upload queue and flushes the queue if + * it exceeds the maximum content length. + * See {@link DocumentUploadQueue#flush}. + * + * @param document The document to be delete from the index. + * @throws IOException If an I/O error occurs during the upload. + * @throws InterruptedException If the upload process is interrupted. + */ + public void add(DeleteDocument document) throws IOException, InterruptedException { + if (document == null) { + return; + } + + final int sizeOfDoc = document.marshalJsonObject().toString().getBytes().length; + if (this.size + sizeOfDoc >= this.maxQueueSize) { + this.flush(); + } + if (document != null) { + documentToDeleteList.add(document); + this.size += sizeOfDoc; + } + } + + public BatchUpdate getBatch() { + return new BatchUpdate( + new ArrayList(this.documentToAddList), + new ArrayList(this.documentToDeleteList)); + } + + public boolean isEmpty() { + // TODO: LENS-843: include partial document updates + return documentToAddList.isEmpty() && documentToDeleteList.isEmpty(); } } diff --git a/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java b/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java new file mode 100644 index 00000000..5e346a41 --- /dev/null +++ b/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java @@ -0,0 +1,192 @@ +package com.coveo.pushapiclient; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.util.ArrayList; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class DocumentUploadQueueTest { + + @Mock + private UploadStrategy uploadStrategy; + + @InjectMocks + private DocumentUploadQueue queue; + + private AutoCloseable closeable; + private DocumentBuilder documentToAdd; + private DeleteDocument documentToDelete; + + private int oneMegaByte = 1 * 1024 * 1024; + + private String generateStringFromBytes(int numBytes) { + // Check if the number of bytes is valid + if (numBytes <= 0) { + return ""; + } + + // Create a byte array with the specified length + byte[] bytes = new byte[numBytes]; + + // Fill the byte array with a pattern of ASCII characters + byte pattern = 65; // ASCII value for 'A' + for (int i = 0; i < numBytes; i++) { + bytes[i] = pattern; + } + + return new String(bytes); + } + + private DocumentBuilder generateDocumentFromSize(int numBytes) { + return new DocumentBuilder("https://my.document.uri?ref=1", + "My bulky document") + .withData(generateStringFromBytes(numBytes)); + } + + @Before + public void setup() { + String twoMegaByteData = generateStringFromBytes(2 * oneMegaByte); + + documentToAdd = new DocumentBuilder( + "https://my.document.uri?ref=1", + "My new document") + .withData(twoMegaByteData); + + documentToDelete = new DeleteDocument("https://my.document.uri?ref=3"); + + closeable = MockitoAnnotations.openMocks(this); + } + + @After + public void closeService() throws Exception { + closeable.close(); + } + + @Test + public void testIsEmpty() throws IOException, InterruptedException { + assertTrue(queue.isEmpty()); + } + + @Test + public void testIsNotEmpty() throws IOException, InterruptedException { + queue.add(documentToAdd); + assertFalse(queue.isEmpty()); + } + + @Test + public void testShouldReturnBatch() throws IOException, InterruptedException { + BatchUpdate batchUpdate = new BatchUpdate( + new ArrayList<>() { + { + add(documentToAdd); + } + }, new ArrayList<>() { + { + add(documentToDelete); + } + }); + queue.add(documentToAdd); + queue.add(documentToDelete); + + assertEquals(batchUpdate, queue.getBatch()); + } + + @Test + public void testFlushShouldNotUploadDocumentaWhenRequiredSizeIsNotMet() throws IOException, InterruptedException { + queue.add(documentToAdd); + queue.add(documentToDelete); + + verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); + } + + @Test + public void testShouldAutomaticallyFlushAccumulatedDocuments() throws IOException, InterruptedException { + DocumentBuilder firstBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder secondBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder thirdBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + ArrayList emptyList = new ArrayList<>(); + BatchUpdate firstBatch = new BatchUpdate( + new ArrayList<>() { + { + add(firstBulkyDocument); + add(secondBulkyDocument); + } + }, emptyList); + + // Adding 3 documents of 2MB to the queue. After adding the first 2 documents, + // the queue size will reach 6MB, which exceeds the maximum queue size + // limit. Therefore, the 2 first added documents will automatically be uploaded + // to the source. + queue.add(firstBulkyDocument); + queue.add(secondBulkyDocument); + + // The 3rd document added to the queue will be included in a separate batch, + // which will not be uploaded unless the `flush()` method is called or until the + // queue size limit has been reached + queue.add(thirdBulkyDocument); + + verify(uploadStrategy, times(1)).apply(any(BatchUpdate.class)); + verify(uploadStrategy, times(1)).apply(firstBatch); + } + + @Test + public void testShouldManuallyFlushAccumulatedDocuments() throws IOException, InterruptedException { + DocumentBuilder firstBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder secondBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder thirdBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + ArrayList emptyList = new ArrayList<>(); + BatchUpdate firstBatch = new BatchUpdate( + new ArrayList<>() { + { + add(firstBulkyDocument); + add(secondBulkyDocument); + } + }, emptyList); + + BatchUpdate secondBatch = new BatchUpdate( + new ArrayList<>() { + { + add(thirdBulkyDocument); + } + }, emptyList); + + // Adding 3 documents of 2MB to the queue. After adding the first 2 documents, + // the queue size will reach 6MB, which exceeds the maximum queue size + // limit. Therefore, the 2 first added documents will automatically be uploaded + // to the source. + queue.add(firstBulkyDocument); + queue.add(secondBulkyDocument); + queue.add(thirdBulkyDocument); + + queue.flush(); + + // Additional flush will have no effect if documents where already flushed + queue.flush(); + + verify(uploadStrategy, times(2)).apply(any(BatchUpdate.class)); + verify(uploadStrategy, times(1)).apply(firstBatch); + verify(uploadStrategy, times(1)).apply(secondBatch); + } + + @Test + public void testAddingEmptyDocument() throws IOException, InterruptedException { + DocumentBuilder nullDocument = null; + + queue.add(nullDocument); + queue.flush(); + + verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); + } +} From aa3335c6d8490a2f625317f4fee3ca85891d87f5 Mon Sep 17 00:00:00 2001 From: Houssein Dhayne <95109658+hdhayneCoveo@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:51:45 -0400 Subject: [PATCH 11/44] feat: add create method in `CatalogSource` and `PushSource` (LENS-874) (#35) --- .../coveo/pushapiclient/CatalogSource.java | 17 ++++++++ .../coveo/pushapiclient/PlatformClient.java | 24 ++++++++++-- .../com/coveo/pushapiclient/PushSource.java | 16 ++++++++ .../java/com/coveo/pushapiclient/Source.java | 2 +- .../com/coveo/pushapiclient/SourceType.java | 39 +++++++++++++++++++ .../pushapiclient/PlatformClientTest.java | 22 ++++++++++- 6 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/coveo/pushapiclient/SourceType.java diff --git a/src/main/java/com/coveo/pushapiclient/CatalogSource.java b/src/main/java/com/coveo/pushapiclient/CatalogSource.java index 7fc9b08a..ea723153 100644 --- a/src/main/java/com/coveo/pushapiclient/CatalogSource.java +++ b/src/main/java/com/coveo/pushapiclient/CatalogSource.java @@ -1,13 +1,30 @@ package com.coveo.pushapiclient; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.net.http.HttpResponse; // TODO: LENS-851 - Make public when ready class CatalogSource implements StreamEnabledSource { private final String apiKey; private final ApiUrl urlExtractor; + + /** + * Creates a Catalog Source in Coveo Org + * + * @param platformClient + * @param name The name of the source to create + * @param sourceVisibility The security option that should be applied to the content of the source. See [Content Security](https://docs.coveo.com/en/1779). + * @return + * @throws IOException + * @throws InterruptedException + */ + public static HttpResponse create(PlatformClient platformClient, String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { + return platformClient.createSource(name, SourceType.CATALOG, sourceVisibility); + } + /** * Create a Catalog source instance from its * Stream API URL diff --git a/src/main/java/com/coveo/pushapiclient/PlatformClient.java b/src/main/java/com/coveo/pushapiclient/PlatformClient.java index 7f0a1705..aa5e2035 100644 --- a/src/main/java/com/coveo/pushapiclient/PlatformClient.java +++ b/src/main/java/com/coveo/pushapiclient/PlatformClient.java @@ -80,19 +80,37 @@ public PlatformClient(String apiKey, String organizationId, Environment environm /** * Create a new push source + * @deprecated + * Please use {@link PlatformClient#createSource(String, SourceType, SourceVisibility)} instead + * + * @param name + * @param sourceVisibility + * @return + * @throws IOException + * @throws InterruptedException + */ + @Deprecated + public HttpResponse createSource(String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { + return createSource(name,SourceType.PUSH,sourceVisibility); + } + + /** + * Create a new source * * @param name The name of the source to create + * @param sourceType The type of the source to create * @param sourceVisibility The security option that should be applied to the content of the source. See [Content Security](https://docs.coveo.com/en/1779). * @return * @throws IOException * @throws InterruptedException */ - public HttpResponse createSource(String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { + public HttpResponse createSource(String name, final SourceType sourceType, SourceVisibility sourceVisibility) throws IOException, InterruptedException { String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); String json = this.toJSON(new HashMap<>() {{ - put("sourceType", "PUSH"); - put("pushEnabled", true); + put("sourceType", sourceType.toString()); + put("pushEnabled", sourceType.isPushEnabled()); + put("streamEnabled", sourceType.isStreamEnabled()); put("name", name); put("sourceVisibility", sourceVisibility); }}); diff --git a/src/main/java/com/coveo/pushapiclient/PushSource.java b/src/main/java/com/coveo/pushapiclient/PushSource.java index 4a17f9a5..b84bf354 100644 --- a/src/main/java/com/coveo/pushapiclient/PushSource.java +++ b/src/main/java/com/coveo/pushapiclient/PushSource.java @@ -33,6 +33,21 @@ public String getApiKey() { return this.apiKey; } + /** + * Creates a push Source in Coveo Org + * + * @param platformClient + * @param name + * @param name The name of the source to create + * @param sourceVisibility The security option that should be applied to the content of the source. See [Content Security](https://docs.coveo.com/en/1779). + * @return + * @throws IOException + * @throws InterruptedException + */ + public static HttpResponse create(PlatformClient platformClient, String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { + return platformClient.createSource(name, SourceType.PUSH, sourceVisibility); + } + /** * Create a Push source instance from its * Push API URL @@ -311,4 +326,5 @@ public HttpResponse deleteDocument(String documentId, Boolean deleteChil return this.platformClient.deleteDocument(this.getId(), documentId, deleteChildren); } + } diff --git a/src/main/java/com/coveo/pushapiclient/Source.java b/src/main/java/com/coveo/pushapiclient/Source.java index 2288d944..475d3e5c 100644 --- a/src/main/java/com/coveo/pushapiclient/Source.java +++ b/src/main/java/com/coveo/pushapiclient/Source.java @@ -53,7 +53,7 @@ public Source(String apiKey, String organizationId, Environment environment) { * @throws InterruptedException */ public HttpResponse create(String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { - return this.platformClient.createSource(name, sourceVisibility); + return this.platformClient.createSource(name, SourceType.PUSH, sourceVisibility); } /** diff --git a/src/main/java/com/coveo/pushapiclient/SourceType.java b/src/main/java/com/coveo/pushapiclient/SourceType.java new file mode 100644 index 00000000..3251aa46 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/SourceType.java @@ -0,0 +1,39 @@ +package com.coveo.pushapiclient; + +public enum SourceType implements SourceTypeInterface{ + PUSH{ + public String toString() { + return "PUSH"; + } + public boolean isPushEnabled(){ return true;} + + @Override + public boolean isStreamEnabled() { + return false; + } + + }, + CATALOG{ + public String toString() { + return "CATALOG"; + } + + @Override + public boolean isPushEnabled() { + return true; + } + + @Override + public boolean isStreamEnabled() { + return true; + } + }, +} + +interface SourceTypeInterface { + + String toString(); + boolean isPushEnabled(); + boolean isStreamEnabled(); + +} diff --git a/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java b/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java index b8b3d779..20eda8af 100644 --- a/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java +++ b/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java @@ -108,8 +108,8 @@ public void setupClient() { } @Test - public void testCreateSource() throws IOException, InterruptedException { - client.createSource("the_name", SourceVisibility.SECURED); + public void testCreatePushSource() throws IOException, InterruptedException { + client.createSource("the_name", SourceType.PUSH, SourceVisibility.SECURED); verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); assertEquals("POST", argument.getValue().method()); @@ -124,6 +124,24 @@ public void testCreateSource() throws IOException, InterruptedException { assertEquals(true, requestBody.get("pushEnabled")); } + @Test + public void testCreateCatalogSource() throws IOException, InterruptedException { + client.createSource("the_name", SourceType.CATALOG, SourceVisibility.SECURED); + verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources")); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + assertEquals("the_name", requestBody.get("name")); + assertEquals(SourceVisibility.SECURED.toString(), requestBody.get("sourceVisibility")); + assertEquals("CATALOG", requestBody.get("sourceType")); + assertEquals(true, requestBody.get("pushEnabled")); + assertEquals(true, requestBody.get("streamEnabled")); + } + @Test public void testCreateOrUpdateSecurityIdentity() throws IOException, InterruptedException { client.createOrUpdateSecurityIdentity("my_provider", securityIdentityModel()); From 0158c9910dc2404a15c0d1d0b2b329f18719b09a Mon Sep 17 00:00:00 2001 From: Houssein Dhayne <95109658+hdhayneCoveo@users.noreply.github.com> Date: Thu, 8 Jun 2023 13:26:09 -0400 Subject: [PATCH 12/44] fix: bug related to the type expected of delete documents --- samples/PushBatchOfDocuments.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/PushBatchOfDocuments.java b/samples/PushBatchOfDocuments.java index 19580662..e0f96bdd 100644 --- a/samples/PushBatchOfDocuments.java +++ b/samples/PushBatchOfDocuments.java @@ -1,4 +1,5 @@ import com.coveo.pushapiclient.BatchUpdate; +import com.coveo.pushapiclient.DeleteDocument; import com.coveo.pushapiclient.DocumentBuilder; import com.coveo.pushapiclient.Source; @@ -13,14 +14,14 @@ public static void main(String[] args) { DocumentBuilder firstDocumentToAdd = new DocumentBuilder("https://my.document.uri?ref=1", "My first document title"); DocumentBuilder secondDocumentToAdd = new DocumentBuilder("https://my.document.uri?ref=2", "My second document title"); - DocumentBuilder firstDocumentToDelete = new DocumentBuilder("https://my.document.uri?ref=3", "My document to delete"); + DeleteDocument firstDocumentToDelete = new DeleteDocument("https://my.document.uri?ref=3"); ArrayList listOfDocumentsToAddOrUpdate = new ArrayList<>() {{ add(firstDocumentToAdd); add(secondDocumentToAdd); }}; - ArrayList listOfDocumentsToDelete = new ArrayList<>() {{ + ArrayList listOfDocumentsToDelete = new ArrayList<>() {{ add(firstDocumentToDelete); }}; From ea3153ca2367bfb0c24f04cf1297a9d20e5a8fb8 Mon Sep 17 00:00:00 2001 From: Houssein Dhayne <95109658+hdhayneCoveo@users.noreply.github.com> Date: Thu, 8 Jun 2023 13:30:29 -0400 Subject: [PATCH 13/44] docs: create Sample Code classes to create push and Catalog Source in Coveo and instance Java classes in different ways (#39) --- samples/CreateCoveoSource.java | 27 +++++++++++++++++++++++++++ samples/CreateSource.java | 1 + samples/InstantiateSource.java | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 samples/CreateCoveoSource.java create mode 100644 samples/InstantiateSource.java diff --git a/samples/CreateCoveoSource.java b/samples/CreateCoveoSource.java new file mode 100644 index 00000000..a5dc6215 --- /dev/null +++ b/samples/CreateCoveoSource.java @@ -0,0 +1,27 @@ +import com.coveo.pushapiclient.CatalogSource; +import com.coveo.pushapiclient.PlatformClient; +import com.coveo.pushapiclient.PushSource; +import com.coveo.pushapiclient.SourceVisibility; + +import java.io.IOException; +import java.net.http.HttpResponse; + + + +public class CreateCoveoSource { + public static void main(String[] args) { + PlatformClient platformClient = new PlatformClient("my_api_key", "my_org_id"); + try { + HttpResponse pushResponse = PushSource.create(platformClient, "the_name_of_my_source", SourceVisibility.SHARED); + System.out.println(String.format("Push Source creation status: %s", pushResponse.statusCode())); + System.out.println(String.format("Push Source creation response: %s", pushResponse.body())); + + HttpResponse response = CatalogSource.create(platformClient, "the_name_of_my_source", SourceVisibility.SHARED); + System.out.println(String.format("Catalog Source creation status: %s", response.statusCode())); + System.out.println(String.format("Catalog Source creation response: %s", response.body())); + + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/samples/CreateSource.java b/samples/CreateSource.java index 41b19c5e..9e84669b 100644 --- a/samples/CreateSource.java +++ b/samples/CreateSource.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.net.http.HttpResponse; +// TODO: LENS-844 - Deprecate class public class CreateSource { public static void main(String[] args) { PlatformUrl platformUrl = new PlatformUrlBuilder() diff --git a/samples/InstantiateSource.java b/samples/InstantiateSource.java new file mode 100644 index 00000000..721e1f65 --- /dev/null +++ b/samples/InstantiateSource.java @@ -0,0 +1,20 @@ +import com.coveo.pushapiclient.*; + +import java.net.MalformedURLException; +import java.net.URL; + +public class InstantiateSource { + public static void main(String[] args) throws MalformedURLException { + //create source from url + URL url = new URL("https://api-eu.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents"); + PushSource pushSource1 = new PushSource("my_api_key", url); + CatalogSource catalogSource1 = new CatalogSource("my_api_key", url); + + + //create source from platform config + PlatformUrl platformUrl = new PlatformUrlBuilder().withEnvironment(Environment.PRODUCTION).withRegion(Region.EU).build(); + PushSource pushSource2 = PushSource.fromPlatformUrl("my_api_key","my_organization_id","my_source_id", platformUrl); + CatalogSource catalogSource2 = CatalogSource.fromPlatformUrl("my_api_key","my_organization_id","my_source_id", platformUrl); + + } +} From 2631e74fa3fa68253ce8e5e9fc3af9493dd14a1b Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 9 Jun 2023 11:53:20 -0400 Subject: [PATCH 14/44] feat: implement `PushService` class (#34) https://coveord.atlassian.net/browse/LENS-837 --------- Co-authored-by: Benjamin Taillon <54454747+btaillon@users.noreply.github.com> Co-authored-by: jpmarceau <39384459+jpmarceau@users.noreply.github.com> Co-authored-by: Mohan Raj Rajamanickam <128537068+mrrajamanickam-coveo@users.noreply.github.com> --- .../pushapiclient/DocumentUploadQueue.java | 16 ++-- .../com/coveo/pushapiclient/PushService.java | 51 +++++++++++++ .../pushapiclient/PushServiceInternal.java | 24 ++++++ .../DocumentUploadQueueTest.java | 14 +++- .../PushServiceInternalTest.java | 75 +++++++++++++++++++ 5 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/coveo/pushapiclient/PushService.java create mode 100644 src/main/java/com/coveo/pushapiclient/PushServiceInternal.java create mode 100644 src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index 79014137..66355664 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -61,18 +61,16 @@ public void add(DocumentBuilder document) throws IOException, InterruptedExcepti if (this.size + sizeOfDoc >= this.maxQueueSize) { this.flush(); } - if (document != null) { - documentToAddList.add(document); - this.size += sizeOfDoc; - } + documentToAddList.add(document); + this.size += sizeOfDoc; } /** - * Adds a {@link DeleteDocument} to the upload queue and flushes the queue if + * Adds the {@link DeleteDocument} to the upload queue and flushes the queue if * it exceeds the maximum content length. * See {@link DocumentUploadQueue#flush}. * - * @param document The document to be delete from the index. + * @param document The document to be deleted from the index. * @throws IOException If an I/O error occurs during the upload. * @throws InterruptedException If the upload process is interrupted. */ @@ -85,10 +83,8 @@ public void add(DeleteDocument document) throws IOException, InterruptedExceptio if (this.size + sizeOfDoc >= this.maxQueueSize) { this.flush(); } - if (document != null) { - documentToDeleteList.add(document); - this.size += sizeOfDoc; - } + documentToDeleteList.add(document); + this.size += sizeOfDoc; } public BatchUpdate getBatch() { diff --git a/src/main/java/com/coveo/pushapiclient/PushService.java b/src/main/java/com/coveo/pushapiclient/PushService.java new file mode 100644 index 00000000..185203f0 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/PushService.java @@ -0,0 +1,51 @@ +package com.coveo.pushapiclient; + +import java.io.IOException; +import java.net.http.HttpResponse; + +import com.google.gson.Gson; + +public class PushService { + private final PushEnabledSource source; + private final PlatformClient platformClient; + private PushServiceInternal service; + + public PushService(PushEnabledSource source) { + String apiKey = source.getApiKey(); + String organizationId = source.getOrganizationId(); + PlatformUrl platformUrl = source.getPlatformUrl(); + UploadStrategy uploader = this.getUploadStrategy(); + DocumentUploadQueue queue = new DocumentUploadQueue(uploader); + + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + this.service = new PushServiceInternal(queue); + this.source = source; + } + + public void addOrUpdate(DocumentBuilder document) throws IOException, InterruptedException { + // TODO: LENS-843: include partial document updates + this.service.addOrUpdate(document); + } + + public void delete(DeleteDocument document) throws IOException, InterruptedException { + this.service.delete(document); + } + + public void close() throws IOException, InterruptedException { + this.service.close(); + } + + private UploadStrategy getUploadStrategy() { + return (batchUpdate) -> { + String sourceId = this.getSourceId(); + HttpResponse resFileContainer = this.platformClient.createFileContainer(); + FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); + this.platformClient.uploadContentToFileContainer(fileContainer, new Gson().toJson(batchUpdate.marshal())); + return this.platformClient.pushFileContainerContent(sourceId, fileContainer); + }; + } + + private String getSourceId() { + return this.source.getId(); + } +} diff --git a/src/main/java/com/coveo/pushapiclient/PushServiceInternal.java b/src/main/java/com/coveo/pushapiclient/PushServiceInternal.java new file mode 100644 index 00000000..7f3f0c4c --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/PushServiceInternal.java @@ -0,0 +1,24 @@ +package com.coveo.pushapiclient; + +import java.io.IOException; + +public class PushServiceInternal { + private DocumentUploadQueue queue; + + public PushServiceInternal(DocumentUploadQueue queue) { + this.queue = queue; + } + + public void addOrUpdate(DocumentBuilder document) throws IOException, InterruptedException { + this.queue.add(document); + } + + public void delete(DeleteDocument document) throws IOException, InterruptedException { + this.queue.add(document); + } + + public void close() throws IOException, InterruptedException { + queue.flush(); + } + +} diff --git a/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java b/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java index 5e346a41..97c11087 100644 --- a/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java +++ b/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java @@ -104,10 +104,17 @@ public void testShouldReturnBatch() throws IOException, InterruptedException { } @Test - public void testFlushShouldNotUploadDocumentaWhenRequiredSizeIsNotMet() throws IOException, InterruptedException { + public void testFlushShouldNotUploadDocumentsWhenRequiredSizeIsNotMet() throws IOException, InterruptedException { + // Adding 2MB document to the queue => queue has now 3MB of free space + // (5MB - 2MB = 3MB) queue.add(documentToAdd); + // Adding 2MB document to the queue => queue has now 1MB of free space + // (3MB - 2MB = 1MB) queue.add(documentToDelete); + // The maximum queue size has not been reached yet (1MB left of free space). + // Therefore, the accumulated documents will not be automatically flushed. + // Unless the user runs `.flush()` the queue will keep the 4MB of documents verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); } @@ -127,10 +134,11 @@ public void testShouldAutomaticallyFlushAccumulatedDocuments() throws IOExceptio // Adding 3 documents of 2MB to the queue. After adding the first 2 documents, // the queue size will reach 6MB, which exceeds the maximum queue size - // limit. Therefore, the 2 first added documents will automatically be uploaded - // to the source. + // limit by 1MB. Therefore, the 2 first added documents will automatically be + // uploaded to the source. queue.add(firstBulkyDocument); queue.add(secondBulkyDocument); + verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); // The 3rd document added to the queue will be included in a separate batch, // which will not be uploaded unless the `flush()` method is called or until the diff --git a/src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java b/src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java new file mode 100644 index 00000000..2a214f7e --- /dev/null +++ b/src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java @@ -0,0 +1,75 @@ +package com.coveo.pushapiclient; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.coveo.pushapiclient.exceptions.NoOpenStreamException; + +import java.io.IOException; +import java.net.http.HttpResponse; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class PushServiceInternalTest { + @Mock + private DocumentUploadQueue queue; + + @InjectMocks + private PushServiceInternal service; + + @Mock + private HttpResponse httpResponse; + + private AutoCloseable closeable; + private DocumentBuilder documentA; + private DocumentBuilder documentB; + private DeleteDocument documentC; + + @Before + public void setUp() throws Exception { + documentA = new DocumentBuilder("https://my.document.uri?ref=1", "My first document title"); + documentB = new DocumentBuilder("https://my.document.uri?ref=2", "My second document title"); + documentC = new DeleteDocument("https://my.document.uri?ref=3"); + + closeable = MockitoAnnotations.openMocks(this); + + } + + @After + public void closeService() throws Exception { + closeable.close(); + } + + @Test + public void testShouldAddNewDocumentToQueue() throws IOException, InterruptedException { + service.addOrUpdate(documentA); + service.addOrUpdate(documentB); + + verify(this.queue, times(1)).add(documentA); + verify(this.queue, times(1)).add(documentB); + } + + @Test + public void testAddShouldAddDocumentToDeleteToQueue() throws IOException, InterruptedException { + service.delete(documentC); + + verify(queue, times(1)).add(documentC); + } + + @Test + public void testCloseShouldFlushBufferedDocuments() + throws IOException, InterruptedException, NoOpenStreamException { + service.addOrUpdate(documentA); + service.addOrUpdate(documentB); + service.delete(documentC); + service.close(); + + verify(queue, times(1)).flush(); + } + +} \ No newline at end of file From d9b0b47fbb449f5499473b329c8dcbbdc3364247 Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 9 Jun 2023 11:56:39 -0400 Subject: [PATCH 15/44] ci: ensure semantic title (#41) * ci: ensure semantic title * ci: remove unnecessary config file --- .github/workflows/pr-title-semantic-lint.yml | 16 ++++ .gitignore | 1 + package-lock.json | 95 ++++++++++++++++++++ package.json | 16 ++++ 4 files changed, 128 insertions(+) create mode 100644 .github/workflows/pr-title-semantic-lint.yml create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.github/workflows/pr-title-semantic-lint.yml b/.github/workflows/pr-title-semantic-lint.yml new file mode 100644 index 00000000..96bf265e --- /dev/null +++ b/.github/workflows/pr-title-semantic-lint.yml @@ -0,0 +1,16 @@ +name: PrTitleSemanticLint +on: + pull_request: + branches: [master] + types: [opened, edited, synchronize, reopened] +jobs: + Lint: + runs-on: ubuntu-20.04 + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 + - name: Ensure PR Title is Semantic + run: | + npm ci + npx @coveo/is-pr-title-semantic diff --git a/.gitignore b/.gitignore index d5a7ca72..5fc3f8c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +node_modules /target/ .env /.idea/ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..62b17eaf --- /dev/null +++ b/package-lock.json @@ -0,0 +1,95 @@ +{ + "name": "publish-java-package-with-maven-on-github-packages", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "publish-java-package-with-maven-on-github-packages", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "@commitlint/config-conventional": "17.4.4" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "17.4.4", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.4.4.tgz", + "integrity": "sha512-u6ztvxqzi6NuhrcEDR7a+z0yrh11elY66nRrQIpqsqW6sZmpxYkDLtpRH8jRML+mmxYQ8s4qqF06Q/IQx5aJeQ==", + "dev": true, + "dependencies": { + "conventional-changelog-conventionalcommits": "^5.0.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", + "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..e946eeb3 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "publish-java-package-with-maven-on-github-packages", + "private": true, + "version": "1.0.0", + "author": "Coveo", + "description": "CI related stuff only", + "license": "Apache-2.0", + "devDependencies": { + "@commitlint/config-conventional": "17.4.4" + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + } +} \ No newline at end of file From 8a0f6b6576a6f72c2ea1424317645cc2d2dbc075 Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 9 Jun 2023 12:41:52 -0400 Subject: [PATCH 16/44] ci: format code base (#44) https://coveord.atlassian.net/browse/LENS-905 --- .github/workflows/build.yml | 5 + README.md | 9 + pom.xml | 55 +- .../com/coveo/pushapiclient/AliasMapping.java | 11 +- .../AnySecurityIdentityBuilder.java | 40 +- .../java/com/coveo/pushapiclient/ApiUrl.java | 204 ++-- .../com/coveo/pushapiclient/BaseSource.java | 49 +- .../coveo/pushapiclient/BatchIdentity.java | 71 +- .../pushapiclient/BatchIdentityRecord.java | 38 +- .../com/coveo/pushapiclient/BatchUpdate.java | 89 +- .../pushapiclient/BatchUpdateRecord.java | 83 +- .../coveo/pushapiclient/CatalogSource.java | 262 ++-- .../pushapiclient/CompressedBinaryData.java | 107 +- .../coveo/pushapiclient/CompressionType.java | 54 +- .../coveo/pushapiclient/DeleteDocument.java | 34 +- .../com/coveo/pushapiclient/Document.java | 274 ++--- .../coveo/pushapiclient/DocumentBuilder.java | 743 ++++++------ .../pushapiclient/DocumentPermissions.java | 31 +- .../pushapiclient/DocumentUploadQueue.java | 158 ++- .../com/coveo/pushapiclient/Environment.java | 26 +- .../coveo/pushapiclient/FileContainer.java | 10 +- .../GroupSecurityIdentityBuilder.java | 103 +- .../coveo/pushapiclient/IdentityModel.java | 16 +- .../coveo/pushapiclient/PlatformClient.java | 1063 +++++++++-------- .../com/coveo/pushapiclient/PlatformUrl.java | 72 +- .../pushapiclient/PlatformUrlBuilder.java | 26 +- .../coveo/pushapiclient/PushAPIStatus.java | 11 +- .../pushapiclient/PushEnabledSource.java | 4 +- .../com/coveo/pushapiclient/PushService.java | 89 +- .../pushapiclient/PushServiceInternal.java | 27 +- .../com/coveo/pushapiclient/PushSource.java | 566 +++++---- .../java/com/coveo/pushapiclient/Region.java | 26 +- .../coveo/pushapiclient/SecurityIdentity.java | 58 +- .../SecurityIdentityAliasModel.java | 15 +- .../SecurityIdentityBatchConfig.java | 79 +- .../SecurityIdentityBatchResponse.java | 31 +- .../SecurityIdentityBuilder.java | 17 +- .../pushapiclient/SecurityIdentityDelete.java | 60 +- .../SecurityIdentityDeleteOptions.java | 80 +- .../pushapiclient/SecurityIdentityModel.java | 15 +- .../SecurityIdentityModelBase.java | 12 +- .../pushapiclient/SecurityIdentityType.java | 40 +- .../java/com/coveo/pushapiclient/Source.java | 446 +++---- .../com/coveo/pushapiclient/SourceType.java | 65 +- .../coveo/pushapiclient/SourceVisibility.java | 43 +- .../pushapiclient/StreamEnabledSource.java | 4 +- .../coveo/pushapiclient/StreamResponse.java | 9 +- .../coveo/pushapiclient/StreamService.java | 200 ++-- .../pushapiclient/StreamServiceInternal.java | 84 +- .../coveo/pushapiclient/UploadStrategy.java | 2 +- .../UserSecurityIdentityBuilder.java | 138 ++- .../VirtualGroupSecurityIdentityBuilder.java | 104 +- .../exceptions/NoOpenStreamException.java | 6 +- .../com/coveo/pushapiclient/ApiUrlTest.java | 156 +-- .../pushapiclient/BatchUpdateRecordTest.java | 106 +- .../coveo/pushapiclient/BatchUpdateTest.java | 147 ++- .../CompressedBinaryDataTest.java | 96 +- .../pushapiclient/DocumentBuilderTest.java | 719 ++++++----- .../DocumentUploadQueueTest.java | 346 +++--- .../GroupSecurityIdentityBuilderTest.java | 121 +- .../pushapiclient/PlatformClientTest.java | 760 +++++++----- .../pushapiclient/PlatformUrlBuilderTest.java | 120 +- .../PushServiceInternalTest.java | 123 +- .../SecurityIdentityBatchConfigTest.java | 94 +- .../SecurityIdentityDeleteOptionsTest.java | 100 +- .../SecurityIdentityDeleteTest.java | 111 +- .../StreamServiceInternalTest.java | 129 +- .../coveo/pushapiclient/StringSubscriber.java | 76 +- .../UserSecurityIdentityBuilderTest.java | 151 +-- ...rtualGroupSecurityIdentityBuilderTest.java | 121 +- 70 files changed, 4779 insertions(+), 4561 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1768f2ff..96b6c600 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,10 +15,15 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Set up JDK 11 uses: actions/setup-java@v2 with: java-version: '11' distribution: 'adopt' + + - name: Validate code format + run: mvn spotless:check + - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/README.md b/README.md index 4d0a54e0..67c9cd4d 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,15 @@ public class PushOneDocument { ``` +## Local Setup to Contribute + +### Formatting + +This project uses [Google Java Format](https://github.com/google/google-java-format), so make sure your code is properly formatted before opening a pull request. +```bash +mvn spotless:apply +``` + ## Release * Tag the commit following semver. diff --git a/pom.xml b/pom.xml index 142e7175..9c4183c9 100644 --- a/pom.xml +++ b/pom.xml @@ -49,26 +49,50 @@ + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.0 + + + + attach-sources + + jar-no-fork + + + + + + + + com.diffplug.spotless + spotless-maven-plugin + ${spotless.version} + + + + src/main/java/**/*.java + src/test/java/**/*.java + + + + + + + + + + + release - - org.apache.maven.plugins - maven-source-plugin - 3.0.0 - - - - - attach-sources - - jar-no-fork - - - - org.apache.maven.plugins maven-javadoc-plugin @@ -169,5 +193,6 @@ 11 11 UTF-8 + 2.37.0 \ No newline at end of file diff --git a/src/main/java/com/coveo/pushapiclient/AliasMapping.java b/src/main/java/com/coveo/pushapiclient/AliasMapping.java index c43ad1e9..3c9866a8 100644 --- a/src/main/java/com/coveo/pushapiclient/AliasMapping.java +++ b/src/main/java/com/coveo/pushapiclient/AliasMapping.java @@ -3,10 +3,11 @@ import java.util.Map; public class AliasMapping extends IdentityModel { - public final String provider; + public final String provider; - public AliasMapping(String provider, String name, SecurityIdentityType type, Map additionalInfo) { - super(name, type, additionalInfo); - this.provider = provider; - } + public AliasMapping( + String provider, String name, SecurityIdentityType type, Map additionalInfo) { + super(name, type, additionalInfo); + this.provider = provider; + } } diff --git a/src/main/java/com/coveo/pushapiclient/AnySecurityIdentityBuilder.java b/src/main/java/com/coveo/pushapiclient/AnySecurityIdentityBuilder.java index b6ee814f..f1ef831c 100644 --- a/src/main/java/com/coveo/pushapiclient/AnySecurityIdentityBuilder.java +++ b/src/main/java/com/coveo/pushapiclient/AnySecurityIdentityBuilder.java @@ -3,25 +3,29 @@ import java.util.Arrays; public class AnySecurityIdentityBuilder implements SecurityIdentityBuilder { - private final String[] identities; - private final SecurityIdentityType securityIdentityType; - private final String securityProvider; + private final String[] identities; + private final SecurityIdentityType securityIdentityType; + private final String securityProvider; - public AnySecurityIdentityBuilder(String identity, SecurityIdentityType securityIdentityType, String securityProvider) { - this.identities = new String[]{identity}; - this.securityIdentityType = securityIdentityType; - this.securityProvider = securityProvider; - } + public AnySecurityIdentityBuilder( + String identity, SecurityIdentityType securityIdentityType, String securityProvider) { + this.identities = new String[] {identity}; + this.securityIdentityType = securityIdentityType; + this.securityProvider = securityProvider; + } - public AnySecurityIdentityBuilder(String[] identities, SecurityIdentityType securityIdentityType, String securityProvider) { - this.identities = identities; - this.securityIdentityType = securityIdentityType; - this.securityProvider = securityProvider; - } + public AnySecurityIdentityBuilder( + String[] identities, SecurityIdentityType securityIdentityType, String securityProvider) { + this.identities = identities; + this.securityIdentityType = securityIdentityType; + this.securityProvider = securityProvider; + } - public SecurityIdentity[] build() { - return Arrays.stream(this.identities) - .map(identity -> new SecurityIdentity(identity, this.securityIdentityType, this.securityProvider)) - .toArray(SecurityIdentity[]::new); - } + public SecurityIdentity[] build() { + return Arrays.stream(this.identities) + .map( + identity -> + new SecurityIdentity(identity, this.securityIdentityType, this.securityProvider)) + .toArray(SecurityIdentity[]::new); + } } diff --git a/src/main/java/com/coveo/pushapiclient/ApiUrl.java b/src/main/java/com/coveo/pushapiclient/ApiUrl.java index b416576d..55d1f27a 100644 --- a/src/main/java/com/coveo/pushapiclient/ApiUrl.java +++ b/src/main/java/com/coveo/pushapiclient/ApiUrl.java @@ -9,114 +9,118 @@ import java.util.regex.Pattern; /** - * Private util class to extract dynamic parts from a API URL - * Handles extraction of identifiers and platform URL from a source URL. - * - * @See https://docs.coveo.com/en/1546#push-api-url - * https://docs.coveo.com/en/3295#stream-api-url + * Private util class to extract dynamic parts from a API URL Handles extraction of identifiers and + * platform URL from a source URL. @See https://docs.coveo.com/en/1546#push-api-url + * https://docs.coveo.com/en/3295#stream-api-url */ class ApiUrl { - private final String organizationId; - private final String sourceId; - private final PlatformUrl platformUrl; - private final String sourceUrl; - - public ApiUrl(URL sourceUrl) throws MalformedURLException { - List identifiers = this.extractIdentifiers(sourceUrl); - this.organizationId = identifiers.get(0); - this.sourceId = identifiers.get(1); - this.sourceUrl = sourceUrl.toString(); - this.platformUrl = this.extractPlatformUrl(sourceUrl); + private final String organizationId; + private final String sourceId; + private final PlatformUrl platformUrl; + private final String sourceUrl; + + public ApiUrl(URL sourceUrl) throws MalformedURLException { + List identifiers = this.extractIdentifiers(sourceUrl); + this.organizationId = identifiers.get(0); + this.sourceId = identifiers.get(1); + this.sourceUrl = sourceUrl.toString(); + this.platformUrl = this.extractPlatformUrl(sourceUrl); + } + + public ApiUrl(String organizationId, String sourceId, PlatformUrl platformUrl) { + this.organizationId = organizationId; + this.sourceId = sourceId; + this.platformUrl = platformUrl; + this.sourceUrl = + String.format( + "https://api.cloud.coveo.com/push/v1/organizations/%s/sources/%s", + this.organizationId, this.sourceId); + } + + public String getUrl() { + return this.sourceUrl; + } + + public String getOrganizationId() { + return this.organizationId; + } + + public String getSourceId() { + return this.sourceId; + } + + public PlatformUrl getPlatformUrl() { + return this.platformUrl; + } + + private List extractIdentifiers(URL sourceUrl) throws MalformedURLException { + String host = sourceUrl.getPath(); + Pattern pattern = Pattern.compile("/push/v1/organizations/([^/]+)/sources/([^/]+)"); + Matcher matcher = pattern.matcher(host); + + if (matcher.find()) { + String organizationId = matcher.group(1); + String sourceId = matcher.group(2); + return Arrays.asList(organizationId, sourceId); } - public ApiUrl(String organizationId, String sourceId, PlatformUrl platformUrl) { - this.organizationId = organizationId; - this.sourceId = sourceId; - this.platformUrl = platformUrl; - this.sourceUrl = String.format("https://api.cloud.coveo.com/push/v1/organizations/%s/sources/%s", - this.organizationId, this.sourceId); + String errorMessage = + this.getErrorMessage( + "Unable to find organization and source ids from the provided API url"); + throw new MalformedURLException(errorMessage); + } + + private PlatformUrl extractPlatformUrl(URL sourceUrl) throws MalformedURLException { + String host = sourceUrl.getHost(); + Pattern pattern = Pattern.compile("api([a-z]*)([a-z-]*)\\.cloud\\.coveo\\.com"); + Matcher matcher = pattern.matcher(host); + + if (matcher.find()) { + String extractedEnvironment = matcher.group(1); + String extractedRegion = matcher.group(2).replace("-", ""); + + Environment urlEnvironment = + extractedEnvironment.isEmpty() + ? PlatformUrl.DEFAULT_ENVIRONMENT + : EnumSet.allOf(Environment.class).stream() + .filter(e -> e.getValue().equalsIgnoreCase(extractedEnvironment)) + .findFirst() + .orElseThrow( + () -> + new MalformedURLException( + String.format( + "Invalid platform environment '%s'", extractedEnvironment))); + + Region urlRegion = + extractedRegion.isEmpty() + ? PlatformUrl.DEFAULT_REGION + : EnumSet.allOf(Region.class).stream() + .filter(r -> r.getValue().equalsIgnoreCase(extractedRegion)) + .findFirst() + .orElseThrow( + () -> + new MalformedURLException( + String.format("Invalid platform region '%s'", extractedRegion))); + + return new PlatformUrl(urlEnvironment, urlRegion); } - public String getUrl() { - return this.sourceUrl; - } - - public String getOrganizationId() { - return this.organizationId; - } - - public String getSourceId() { - return this.sourceId; - } - - public PlatformUrl getPlatformUrl() { - return this.platformUrl; - } + String invalidHostMessage = this.getErrorMessage("Invalid API URL host"); + throw new MalformedURLException(invalidHostMessage); + } - private List extractIdentifiers(URL sourceUrl) throws MalformedURLException { - String host = sourceUrl.getPath(); - Pattern pattern = Pattern.compile("/push/v1/organizations/([^/]+)/sources/([^/]+)"); - Matcher matcher = pattern.matcher(host); + private String getErrorMessage(String reason) { + String newLine = System.getProperty("line.separator"); + String message = "The provided API URL is invalid"; - if (matcher.find()) { - String organizationId = matcher.group(1); - String sourceId = matcher.group(2); - return Arrays.asList(organizationId, sourceId); - } + message.concat(newLine).concat(reason); - String errorMessage = this - .getErrorMessage("Unable to find organization and source ids from the provided API url"); - throw new MalformedURLException(errorMessage); - } - - private PlatformUrl extractPlatformUrl(URL sourceUrl) throws MalformedURLException { - String host = sourceUrl.getHost(); - Pattern pattern = Pattern.compile("api([a-z]*)([a-z-]*)\\.cloud\\.coveo\\.com"); - Matcher matcher = pattern.matcher(host); - - if (matcher.find()) { - String extractedEnvironment = matcher.group(1); - String extractedRegion = matcher.group(2).replace("-", ""); - - Environment urlEnvironment = extractedEnvironment.isEmpty() - ? PlatformUrl.DEFAULT_ENVIRONMENT - : EnumSet.allOf(Environment.class) - .stream() - .filter(e -> e.getValue().equalsIgnoreCase(extractedEnvironment)) - .findFirst() - .orElseThrow(() -> new MalformedURLException( - String.format("Invalid platform environment '%s'", extractedEnvironment))); - - Region urlRegion = extractedRegion.isEmpty() - ? PlatformUrl.DEFAULT_REGION - : EnumSet.allOf(Region.class) - .stream() - .filter(r -> r.getValue().equalsIgnoreCase(extractedRegion)) - .findFirst() - .orElseThrow(() -> new MalformedURLException( - String.format("Invalid platform region '%s'", extractedRegion))); - - return new PlatformUrl(urlEnvironment, urlRegion); - - } - - String invalidHostMessage = this.getErrorMessage("Invalid API URL host"); - throw new MalformedURLException(invalidHostMessage); - } - - private String getErrorMessage(String reason) { - String newLine = System.getProperty("line.separator"); - String message = "The provided API URL is invalid"; - - message.concat(newLine).concat(reason); - - message - .concat(newLine) - .concat("For a Push Source, visit: https://docs.coveo.com/en/1546") - .concat(newLine) - .concat("For a Catalog Source, visit:https://docs.coveo.com/en/3295"); - - return message; - } + message + .concat(newLine) + .concat("For a Push Source, visit: https://docs.coveo.com/en/1546") + .concat(newLine) + .concat("For a Catalog Source, visit:https://docs.coveo.com/en/3295"); + return message; + } } diff --git a/src/main/java/com/coveo/pushapiclient/BaseSource.java b/src/main/java/com/coveo/pushapiclient/BaseSource.java index a3edd80c..169fd645 100644 --- a/src/main/java/com/coveo/pushapiclient/BaseSource.java +++ b/src/main/java/com/coveo/pushapiclient/BaseSource.java @@ -1,32 +1,31 @@ package com.coveo.pushapiclient; public interface BaseSource { - /** - * Returns the API key used for all operations regarding your source. - * - * @return - */ - String getApiKey(); + /** + * Returns the API key used for all operations regarding your source. + * + * @return + */ + String getApiKey(); - /** - * Returns the {@link PlatformUrl} object associated to the source. - * - * @return - */ - PlatformUrl getPlatformUrl(); + /** + * Returns the {@link PlatformUrl} object associated to the source. + * + * @return + */ + PlatformUrl getPlatformUrl(); - /** - * The unique identifier of your organization. - * - * @return - */ - String getOrganizationId(); - - /** - * The unique identifier of your source. - * - * @return - */ - String getId(); + /** + * The unique identifier of your organization. + * + * @return + */ + String getOrganizationId(); + /** + * The unique identifier of your source. + * + * @return + */ + String getId(); } diff --git a/src/main/java/com/coveo/pushapiclient/BatchIdentity.java b/src/main/java/com/coveo/pushapiclient/BatchIdentity.java index f7d376b8..710e0ee0 100644 --- a/src/main/java/com/coveo/pushapiclient/BatchIdentity.java +++ b/src/main/java/com/coveo/pushapiclient/BatchIdentity.java @@ -2,41 +2,46 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; - import java.util.List; -/** - * See [Manage Batches of Security Identities](https://docs.coveo.com/en/55) - */ +/** See [Manage Batches of Security Identities](https://docs.coveo.com/en/55) */ public class BatchIdentity { - private List members; - private List mappings; - private List deleted; - - public BatchIdentity(List members, List mappings, List deleted) { - this.members = members; - this.mappings = mappings; - this.deleted = deleted; - } - - public BatchIdentityRecord marshal() { - return new BatchIdentityRecord( - this.members.stream().map(s -> new Gson().toJsonTree(s).getAsJsonObject()).toArray(JsonObject[]::new), - this.mappings.stream().map(s -> new Gson().toJsonTree(s).getAsJsonObject()).toArray(JsonObject[]::new), - this.deleted.stream().map(s -> new Gson().toJsonTree(s).getAsJsonObject()).toArray(JsonObject[]::new) - ); - } - - public List getMembers() { - return members; - } - - public List getMappings() { - return mappings; - } - - public List getDeleted() { - return deleted; - } + private List members; + private List mappings; + private List deleted; + + public BatchIdentity( + List members, + List mappings, + List deleted) { + this.members = members; + this.mappings = mappings; + this.deleted = deleted; + } + + public BatchIdentityRecord marshal() { + return new BatchIdentityRecord( + this.members.stream() + .map(s -> new Gson().toJsonTree(s).getAsJsonObject()) + .toArray(JsonObject[]::new), + this.mappings.stream() + .map(s -> new Gson().toJsonTree(s).getAsJsonObject()) + .toArray(JsonObject[]::new), + this.deleted.stream() + .map(s -> new Gson().toJsonTree(s).getAsJsonObject()) + .toArray(JsonObject[]::new)); + } + + public List getMembers() { + return members; + } + + public List getMappings() { + return mappings; + } + + public List getDeleted() { + return deleted; + } } diff --git a/src/main/java/com/coveo/pushapiclient/BatchIdentityRecord.java b/src/main/java/com/coveo/pushapiclient/BatchIdentityRecord.java index c807cc1d..f0670036 100644 --- a/src/main/java/com/coveo/pushapiclient/BatchIdentityRecord.java +++ b/src/main/java/com/coveo/pushapiclient/BatchIdentityRecord.java @@ -2,30 +2,28 @@ import com.google.gson.JsonObject; -/** - * See [BatchIdentityBody](https://docs.coveo.com/en/139#batchidentitybody) - */ +/** See [BatchIdentityBody](https://docs.coveo.com/en/139#batchidentitybody) */ public class BatchIdentityRecord { - private JsonObject[] members; - private JsonObject[] mappings; - private JsonObject[] deleted; + private JsonObject[] members; + private JsonObject[] mappings; + private JsonObject[] deleted; - public BatchIdentityRecord(JsonObject[] members, JsonObject[] mappings, JsonObject[] deleted) { - this.members = members; - this.mappings = mappings; - this.deleted = deleted; - } + public BatchIdentityRecord(JsonObject[] members, JsonObject[] mappings, JsonObject[] deleted) { + this.members = members; + this.mappings = mappings; + this.deleted = deleted; + } - public JsonObject[] getMembers() { - return members; - } + public JsonObject[] getMembers() { + return members; + } - public JsonObject[] getMappings() { - return mappings; - } + public JsonObject[] getMappings() { + return mappings; + } - public JsonObject[] getDeleted() { - return deleted; - } + public JsonObject[] getDeleted() { + return deleted; + } } diff --git a/src/main/java/com/coveo/pushapiclient/BatchUpdate.java b/src/main/java/com/coveo/pushapiclient/BatchUpdate.java index 2a7efa6d..c251fe5b 100644 --- a/src/main/java/com/coveo/pushapiclient/BatchUpdate.java +++ b/src/main/java/com/coveo/pushapiclient/BatchUpdate.java @@ -1,56 +1,51 @@ package com.coveo.pushapiclient; import com.google.gson.JsonObject; - import java.util.List; import java.util.Objects; -/** - * See [Manage Batches of Items in a Push Source](https://docs.coveo.com/en/90) - */ +/** See [Manage Batches of Items in a Push Source](https://docs.coveo.com/en/90) */ public class BatchUpdate { - private final List addOrUpdate; - private final List delete; - - public BatchUpdate(List addOrUpdate, List delete) { - this.addOrUpdate = addOrUpdate; - this.delete = delete; - } - - public BatchUpdateRecord marshal() { - return new BatchUpdateRecord( - this.addOrUpdate.stream().map(DocumentBuilder::marshalJsonObject).toArray(JsonObject[]::new), - this.delete.stream().map(DeleteDocument::marshalJsonObject).toArray(JsonObject[]::new) - ); - } - - public List getAddOrUpdate() { - return addOrUpdate; - } - - public List getDelete() { - return delete; - } - - @Override - public String toString() { - return "BatchUpdate[" + - "addOrUpdate=" + addOrUpdate + - ", delete=" + delete + - ']'; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - BatchUpdate that = (BatchUpdate) obj; - return addOrUpdate.equals(that.addOrUpdate) && delete.equals(that.delete); - } - - @Override - public int hashCode() { - return Objects.hash(addOrUpdate, delete); - } + private final List addOrUpdate; + private final List delete; + + public BatchUpdate(List addOrUpdate, List delete) { + this.addOrUpdate = addOrUpdate; + this.delete = delete; + } + + public BatchUpdateRecord marshal() { + return new BatchUpdateRecord( + this.addOrUpdate.stream() + .map(DocumentBuilder::marshalJsonObject) + .toArray(JsonObject[]::new), + this.delete.stream().map(DeleteDocument::marshalJsonObject).toArray(JsonObject[]::new)); + } + + public List getAddOrUpdate() { + return addOrUpdate; + } + + public List getDelete() { + return delete; + } + + @Override + public String toString() { + return "BatchUpdate[" + "addOrUpdate=" + addOrUpdate + ", delete=" + delete + ']'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + BatchUpdate that = (BatchUpdate) obj; + return addOrUpdate.equals(that.addOrUpdate) && delete.equals(that.delete); + } + + @Override + public int hashCode() { + return Objects.hash(addOrUpdate, delete); + } } diff --git a/src/main/java/com/coveo/pushapiclient/BatchUpdateRecord.java b/src/main/java/com/coveo/pushapiclient/BatchUpdateRecord.java index 56c90fda..f511d363 100644 --- a/src/main/java/com/coveo/pushapiclient/BatchUpdateRecord.java +++ b/src/main/java/com/coveo/pushapiclient/BatchUpdateRecord.java @@ -1,50 +1,49 @@ package com.coveo.pushapiclient; import com.google.gson.JsonObject; - import java.util.Arrays; -/** - * See [BatchDocumentBody](https://docs.coveo.com/en/75/#batchdocumentbody) - */ +/** See [BatchDocumentBody](https://docs.coveo.com/en/75/#batchdocumentbody) */ public class BatchUpdateRecord { - private final JsonObject[] addOrUpdate; - private final JsonObject[] delete; - - public BatchUpdateRecord(JsonObject[] addOrUpdate, JsonObject[] delete) { - this.addOrUpdate = addOrUpdate; - this.delete = delete; - } - - public JsonObject[] getAddOrUpdate() { - return addOrUpdate; - } - - public JsonObject[] getDelete() { - return delete; - } - - @Override - public String toString() { - return "BatchUpdateRecord[" + - "addOrUpdate=" + Arrays.toString(addOrUpdate) + - ", delete=" + Arrays.toString(delete) + - ']'; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - BatchUpdateRecord that = (BatchUpdateRecord) obj; - return Arrays.equals(addOrUpdate, that.addOrUpdate) && Arrays.equals(delete, that.delete); - } - - @Override - public int hashCode() { - int result = Arrays.hashCode(addOrUpdate); - result = 31 * result + Arrays.hashCode(delete); - return result; - } + private final JsonObject[] addOrUpdate; + private final JsonObject[] delete; + + public BatchUpdateRecord(JsonObject[] addOrUpdate, JsonObject[] delete) { + this.addOrUpdate = addOrUpdate; + this.delete = delete; + } + + public JsonObject[] getAddOrUpdate() { + return addOrUpdate; + } + + public JsonObject[] getDelete() { + return delete; + } + + @Override + public String toString() { + return "BatchUpdateRecord[" + + "addOrUpdate=" + + Arrays.toString(addOrUpdate) + + ", delete=" + + Arrays.toString(delete) + + ']'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + BatchUpdateRecord that = (BatchUpdateRecord) obj; + return Arrays.equals(addOrUpdate, that.addOrUpdate) && Arrays.equals(delete, that.delete); + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(addOrUpdate); + result = 31 * result + Arrays.hashCode(delete); + return result; + } } diff --git a/src/main/java/com/coveo/pushapiclient/CatalogSource.java b/src/main/java/com/coveo/pushapiclient/CatalogSource.java index ea723153..27980c92 100644 --- a/src/main/java/com/coveo/pushapiclient/CatalogSource.java +++ b/src/main/java/com/coveo/pushapiclient/CatalogSource.java @@ -7,165 +7,123 @@ // TODO: LENS-851 - Make public when ready class CatalogSource implements StreamEnabledSource { - private final String apiKey; - private final ApiUrl urlExtractor; + private final String apiKey; + private final ApiUrl urlExtractor; + /** + * Creates a Catalog Source in Coveo Org + * + * @param platformClient + * @param name The name of the source to create + * @param sourceVisibility The security option that should be applied to the content of the + * source. See [Content Security](https://docs.coveo.com/en/1779). + * @return + * @throws IOException + * @throws InterruptedException + */ + public static HttpResponse create( + PlatformClient platformClient, String name, SourceVisibility sourceVisibility) + throws IOException, InterruptedException { + return platformClient.createSource(name, SourceType.CATALOG, sourceVisibility); + } - /** - * Creates a Catalog Source in Coveo Org - * - * @param platformClient - * @param name The name of the source to create - * @param sourceVisibility The security option that should be applied to the content of the source. See [Content Security](https://docs.coveo.com/en/1779). - * @return - * @throws IOException - * @throws InterruptedException - */ - public static HttpResponse create(PlatformClient platformClient, String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { - return platformClient.createSource(name, SourceType.CATALOG, sourceVisibility); - } + /** + * Create a Catalog source instance from its Stream API URL + * + * @param apiKey The API key used for all operations regarding your source. + *

Ensure your API key has the required privileges for the operation you will be performing + * * + *

For more information about which privileges are required, see Privilege Reference. + * @param sourceUrl The URL available when you edit your source in the Coveo Administration + * Console. The URL should contain your ORGANIZATION_ID and SOURCE_ID + * , which are required parameters for all operations regarding your source. + *

Some examples of valid source URLs: + *

+   * https://api.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/stream/open
+   * https://api-eu.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/stream/open
+   *                  
+ * + * @throws MalformedURLException + */ + public CatalogSource(String apiKey, URL sourceUrl) throws MalformedURLException { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(sourceUrl); + } - /** - * Create a Catalog source instance from its - * Stream API URL - * - * @param apiKey The API key used for all operations regarding your source. - *

- * Ensure your API key has the required privileges for the - * operation you will be performing - * * - *

- * For more information about which privileges are required, - * see - * Privilege - * Reference. - * - * @param sourceUrl The URL available when you edit your source in the Coveo - * Administration Console. The URL should contain your - * ORGANIZATION_ID and SOURCE_ID, - * which are required parameters for all operations regarding - * your source. - *

- * Some examples of valid source URLs: - * - *

-     * https://api.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/stream/open
-     * https://api-eu.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/stream/open
-     *                  
- * - * @throws MalformedURLException - */ - public CatalogSource(String apiKey, URL sourceUrl) throws MalformedURLException { - this.apiKey = apiKey; - this.urlExtractor = new ApiUrl(sourceUrl); - } + /** + * Create a Catalog source instance from its Stream API URL + * + * @param apiKey The API key used for all operations regarding your source. + *

Ensure your API key has the required privileges for the operation you will be performing + * * + *

For more information about which privileges are required, see Privilege Reference. + * @param organizationId The unique identifier of your organization. + *

The Organization Id can be retrieved in the URL of your Coveo organization. + * @param sourceId The unique identifier of the target Catalog source. + *

The Source Id can be retrieved when you edit your source in the Coveo Administration + * Console + */ + public static CatalogSource fromPlatformUrl( + String apiKey, String organizationId, String sourceId) { + PlatformUrl platformUrl = + new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); + return new CatalogSource(apiKey, organizationId, sourceId, platformUrl); + } - /** - * Create a Catalog source instance from its - * Stream API URL - * - * @param apiKey The API key used for all operations regarding your - * source. - *

- * Ensure your API key has the required privileges for the - * operation you will be performing - * * - *

- * For more information about which privileges are - * required, - * see - * Privilege - * Reference. - * - * @param organizationId The unique identifier of your organization. - *

- * The Organization Id can be retrieved in the URL of your - * Coveo organization. - * - * @param sourceId The unique identifier of the target Catalog source. - *

- * The Source Id can be retrieved when you edit your - * source in the Coveo - * Administration Console - * - */ - public static CatalogSource fromPlatformUrl(String apiKey, String organizationId, String sourceId) { - PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); - return new CatalogSource(apiKey, organizationId, sourceId, platformUrl); - } + /** + * Create a Catalog source instance from its Stream API URL + * + * @param apiKey The API key used for all operations regarding your source. + *

Ensure your API key has the required privileges for the operation you will be performing + * * + *

For more information about which privileges are required, see Privilege Reference. + * @param organizationId The unique identifier of your organization. + *

The Organization Id can be retrieved in the URL of your Coveo organization. + * @param sourceId The unique identifier of the target Catalog source. + *

The Source Id can be retrieved when you edit your source in the Coveo Administration + * Console + * @param platformUrl The object containing additional information on the URL endpoint. You can + * use the {@link PlatformUrl} when your organization is located in a non-default Coveo + * environement and/or region. When not specified, the default platform URL values will be + * used: {@link PlatformUrl#DEFAULT_ENVIRONMENT} and {@link PlatformUrl#DEFAULT_REGION} + */ + public static CatalogSource fromPlatformUrl( + String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + return new CatalogSource(apiKey, organizationId, sourceId, platformUrl); + } - /** - * Create a Catalog source instance from its - * Stream API URL - * - * @param apiKey The API key used for all operations regarding your - * source. - *

- * Ensure your API key has the required privileges for the - * operation you will be performing - * * - *

- * For more information about which privileges are - * required, - * see - * Privilege - * Reference. - * - * @param organizationId The unique identifier of your organization. - *

- * The Organization Id can be retrieved in the URL of your - * Coveo organization. - * - * @param sourceId The unique identifier of the target Catalog source. - *

- * The Source Id can be retrieved when you edit your - * source in the Coveo - * Administration Console - * - * @param platformUrl The object containing additional information on the - * URL endpoint. - * You can use the {@link PlatformUrl} when your - * organization is located in a non-default Coveo - * environement and/or region. When not specified, the - * default platform URL values will be used: - * {@link PlatformUrl#DEFAULT_ENVIRONMENT} and - * {@link PlatformUrl#DEFAULT_REGION} - * - */ - public static CatalogSource fromPlatformUrl(String apiKey, String organizationId, String sourceId, - PlatformUrl platformUrl) { - return new CatalogSource(apiKey, organizationId, sourceId, platformUrl); - } + private CatalogSource( + String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(organizationId, sourceId, platformUrl); + } - private CatalogSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { - this.apiKey = apiKey; - this.urlExtractor = new ApiUrl(organizationId, sourceId, platformUrl); - } + @Override + public String getOrganizationId() { + return this.urlExtractor.getOrganizationId(); + } - @Override - public String getOrganizationId() { - return this.urlExtractor.getOrganizationId(); - } + @Override + public PlatformUrl getPlatformUrl() { + return this.urlExtractor.getPlatformUrl(); + } - @Override - public PlatformUrl getPlatformUrl() { - return this.urlExtractor.getPlatformUrl(); - } - - @Override - public String getId() { - return this.urlExtractor.getSourceId(); - } - - @Override - public String getApiKey() { - return this.apiKey; - } + @Override + public String getId() { + return this.urlExtractor.getSourceId(); + } + @Override + public String getApiKey() { + return this.apiKey; + } } diff --git a/src/main/java/com/coveo/pushapiclient/CompressedBinaryData.java b/src/main/java/com/coveo/pushapiclient/CompressedBinaryData.java index 4d252e49..d15aafff 100644 --- a/src/main/java/com/coveo/pushapiclient/CompressedBinaryData.java +++ b/src/main/java/com/coveo/pushapiclient/CompressedBinaryData.java @@ -3,56 +3,63 @@ import java.util.Objects; /** - * The original binary item content, compressed using one of the supported compression types (Deflate, GZip, LZMA, Uncompressed, or ZLib), and then Base64 encoded. - *

- * You can use this parameter when you're pushing a compressed binary item (such as XML/HTML, PDF, Word, or binary) whose size is less than 5 MB. - *

- * Whenever you're pushing an item whose size is 5 MB or more, use the CompressedBinaryDataFileId property instead. - *

- * If you're pushing less than 5 MB of textual (non-binary) content, you can use the data property instead. - *

- * See https://docs.coveo.com/en/73 for more information. + * The original binary item content, compressed using one of the supported compression types + * (Deflate, GZip, LZMA, Uncompressed, or ZLib), and then Base64 encoded. + * + *

You can use this parameter when you're pushing a compressed binary item (such as XML/HTML, + * PDF, Word, or binary) whose size is less than 5 MB. + * + *

Whenever you're pushing an item whose size is 5 MB or more, use the CompressedBinaryDataFileId + * property instead. + * + *

If you're pushing less than 5 MB of textual (non-binary) content, you can use the data + * property instead. + * + *

See https://docs.coveo.com/en/73 for more information. */ public class CompressedBinaryData { - private final String data; - private final CompressionType compressionType; - - /** - * @param data The base64 encoded binary data. Example: `eJxzrUjMLchJBQAK4ALN` - * @param compressionType The compression type that was applied to your document. - */ - public CompressedBinaryData(String data, CompressionType compressionType) { - this.data = data; - this.compressionType = compressionType; - } - - public String getData() { - return data; - } - - public CompressionType getCompressionType() { - return compressionType; - } - - @Override - public String toString() { - return "CompressedBinaryData[" + - "data='" + data + '\'' + - ", compressionType=" + compressionType + - ']'; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - CompressedBinaryData that = (CompressedBinaryData) obj; - return Objects.equals(data, that.data) && compressionType == that.compressionType; - } - - @Override - public int hashCode() { - return Objects.hash(data, compressionType); - } -} \ No newline at end of file + private final String data; + private final CompressionType compressionType; + + /** + * @param data The base64 encoded binary data. Example: `eJxzrUjMLchJBQAK4ALN` + * @param compressionType The compression type that was applied to your document. + */ + public CompressedBinaryData(String data, CompressionType compressionType) { + this.data = data; + this.compressionType = compressionType; + } + + public String getData() { + return data; + } + + public CompressionType getCompressionType() { + return compressionType; + } + + @Override + public String toString() { + return "CompressedBinaryData[" + + "data='" + + data + + '\'' + + ", compressionType=" + + compressionType + + ']'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + CompressedBinaryData that = (CompressedBinaryData) obj; + return Objects.equals(data, that.data) && compressionType == that.compressionType; + } + + @Override + public int hashCode() { + return Objects.hash(data, compressionType); + } +} diff --git a/src/main/java/com/coveo/pushapiclient/CompressionType.java b/src/main/java/com/coveo/pushapiclient/CompressionType.java index 8490aafc..2329e47e 100644 --- a/src/main/java/com/coveo/pushapiclient/CompressionType.java +++ b/src/main/java/com/coveo/pushapiclient/CompressionType.java @@ -1,32 +1,30 @@ package com.coveo.pushapiclient; -/** - * The compression type that was applied to your compressed document. - */ +/** The compression type that was applied to your compressed document. */ public enum CompressionType { - UNCOMPRESSED { - public String toString() { - return "UNCOMPRESSED"; - } - }, - DEFLATE { - public String toString() { - return "DEFLATE"; - } - }, - GZIP { - public String toString() { - return "GZIP"; - } - }, - LZMA { - public String toString() { - return "LZMA"; - } - }, - ZLIB { - public String toString() { - return "ZLIB"; - } + UNCOMPRESSED { + public String toString() { + return "UNCOMPRESSED"; } -} \ No newline at end of file + }, + DEFLATE { + public String toString() { + return "DEFLATE"; + } + }, + GZIP { + public String toString() { + return "GZIP"; + } + }, + LZMA { + public String toString() { + return "LZMA"; + } + }, + ZLIB { + public String toString() { + return "ZLIB"; + } + } +} diff --git a/src/main/java/com/coveo/pushapiclient/DeleteDocument.java b/src/main/java/com/coveo/pushapiclient/DeleteDocument.java index 200d7c42..0cb313f5 100644 --- a/src/main/java/com/coveo/pushapiclient/DeleteDocument.java +++ b/src/main/java/com/coveo/pushapiclient/DeleteDocument.java @@ -5,27 +5,23 @@ public class DeleteDocument { - /** - * The documentId of the document. - */ - public String documentId; + /** The documentId of the document. */ + public String documentId; - /** - * Flag to delete children of the document. - */ - public boolean deleteChildren; + /** Flag to delete children of the document. */ + public boolean deleteChildren; - public DeleteDocument(String documentId) { - this.documentId = documentId; - this.deleteChildren = false; - } + public DeleteDocument(String documentId) { + this.documentId = documentId; + this.deleteChildren = false; + } - public DeleteDocument(String documentId, boolean deleteChildren) { - this.documentId = documentId; - this.deleteChildren = deleteChildren; - } + public DeleteDocument(String documentId, boolean deleteChildren) { + this.documentId = documentId; + this.deleteChildren = deleteChildren; + } - public JsonObject marshalJsonObject() { - return new Gson().toJsonTree(this).getAsJsonObject(); - } + public JsonObject marshalJsonObject() { + return new Gson().toJsonTree(this).getAsJsonObject(); + } } diff --git a/src/main/java/com/coveo/pushapiclient/Document.java b/src/main/java/com/coveo/pushapiclient/Document.java index 30161dec..a02e632b 100644 --- a/src/main/java/com/coveo/pushapiclient/Document.java +++ b/src/main/java/com/coveo/pushapiclient/Document.java @@ -3,138 +3,144 @@ import java.util.HashMap; public class Document { - /** - * The metadata key-value pairs for a given document. - *

- * Each metadata in the document must be unique. - *

- * Metadata are case-insensitive (e.g., the Push API considers mykey, MyKey, myKey, MYKEY, etc. as identical). - *

- * See https://docs.coveo.com/en/115 for more information. - */ - public final HashMap metadata; - - /** - * The list of permission sets for this item. - *

- * This is useful when item based security is required (i.e., when security isn't configured at the source level). - *

- * See https://docs.coveo.com/en/107 for more information. - */ - public DocumentPermissions[] permissions; - - /** - * The Uniform Resource Identifier (URI) that uniquely identifies the document in a Coveo index. - *

- * Examples: - * - `http://www.example.com/` - * - `file://folder/text.txt` - */ - public String uri; - - /** - * The documentId of the document. - */ - public String documentId; - - /** - * The title of the document. - */ - public String title; - - /** - * The clickable URI associated with the document. - */ - public String clickableUri; - - /** - * The author of the document. - */ - public String author; - - /** - * The date of the document, represented as an ISO string. - *

- * Optional, will default to indexation date. - */ - public String date; - - /** - * The modified date of the document, represented as an ISO string. - *

- * Optional, will default to indexation date. - */ - public String modifiedDate; - - /** - * The permanent identifier of a document that does not change over time. - *

- * Optional, will be derived from the document URI. - */ - public String permanentId; - - /** - * The unique identifier (URI) of the parent item. - *

- * Specifying a value for this key creates a relationship between the attachment item (child) and its parent item. - *

- * This value also ensures that a parent and all of its attachments will be routed in the same index slice. - */ - public String parentId; - - /** - * The textual (non-binary) content of the item. - *

- * Whenever you're pushing a compressed binary item (such as XML/HTML, PDF, Word, or binary), you should use the CompressedBinaryData or CompressedBinaryDataFileId attribute instead, depending on the content size. - *

- * Accepts 5 MB or less of uncompressed textual data. - *

- * See https://docs.coveo.com/en/73 for more information. - *

- * Example: `This is a simple string that will be used for searchability as well as to generate excerpt and summaries for the document.` - */ - public String data; - - /** - * The original binary item content, compressed using one of the supported compression types (Deflate, GZip, LZMA, Uncompressed, or ZLib), and then Base64 encoded. - *

- * You can use this parameter when you're pushing a compressed binary item (such as XML/HTML, PDF, Word, or binary) whose size is less than 5 MB. - *

- * Whenever you're pushing an item whose size is 5 MB or more, use the CompressedBinaryDataFileId property instead. - *

- * If you're pushing less than 5 MB of textual (non-binary) content, you can use the data property instead. - *

- * See https://docs.coveo.com/en/73 for more information. - */ - public CompressedBinaryData compressedBinaryData; - - /** - * The fileId from the content that has been uploaded to the S3 via a FileContainer. The file is compressed using one of the supported compression types (Deflate, GZip, LZMA, Uncompressed, or ZLib). - *

- * You can use this parameter when you're pushing a compressed binary item (such as XML/HTML, PDF, Word, or binary) whose size is greater than 5 MB. - *

- * Whenever you're pushing an item whose size is less than 5 MB, use the CompressedBinaryData property instead. - *

- * If you're pushing less than 5 MB of textual (non-binary) content, you can use the data property instead. - *

- * See https://docs.coveo.com/en/73 for more information. - */ - public String compressedBinaryDataFileId; - - /** - * The file extension of the data you're pushing. - *

- * This is useful when pushing a compressed item. The converter uses this information to identify how to correctly process the item. - *

- * Values must include the preceding . character. - *

- * Example: `.html` - */ - public String fileExtension; - - public Document() { - this.permissions = new DocumentPermissions[]{new DocumentPermissions()}; - this.metadata = new HashMap(); - } + /** + * The metadata key-value pairs for a given document. + * + *

Each metadata in the document must be unique. + * + *

Metadata are case-insensitive (e.g., the Push API considers mykey, MyKey, myKey, MYKEY, etc. + * as identical). + * + *

See https://docs.coveo.com/en/115 for more information. + */ + public final HashMap metadata; + + /** + * The list of permission sets for this item. + * + *

This is useful when item based security is required (i.e., when security isn't configured at + * the source level). + * + *

See https://docs.coveo.com/en/107 for more information. + */ + public DocumentPermissions[] permissions; + + /** + * The Uniform Resource Identifier (URI) that uniquely identifies the document in a Coveo index. + * + *

Examples: - `http://www.example.com/` - `file://folder/text.txt` + */ + public String uri; + + /** The documentId of the document. */ + public String documentId; + + /** The title of the document. */ + public String title; + + /** The clickable URI associated with the document. */ + public String clickableUri; + + /** The author of the document. */ + public String author; + + /** + * The date of the document, represented as an ISO string. + * + *

Optional, will default to indexation date. + */ + public String date; + + /** + * The modified date of the document, represented as an ISO string. + * + *

Optional, will default to indexation date. + */ + public String modifiedDate; + + /** + * The permanent identifier of a document that does not change over time. + * + *

Optional, will be derived from the document URI. + */ + public String permanentId; + + /** + * The unique identifier (URI) of the parent item. + * + *

Specifying a value for this key creates a relationship between the attachment item (child) + * and its parent item. + * + *

This value also ensures that a parent and all of its attachments will be routed in the same + * index slice. + */ + public String parentId; + + /** + * The textual (non-binary) content of the item. + * + *

Whenever you're pushing a compressed binary item (such as XML/HTML, PDF, Word, or binary), + * you should use the CompressedBinaryData or CompressedBinaryDataFileId attribute instead, + * depending on the content size. + * + *

Accepts 5 MB or less of uncompressed textual data. + * + *

See https://docs.coveo.com/en/73 for more information. + * + *

Example: `This is a simple string that will be used for searchability as well as to generate + * excerpt and summaries for the document.` + */ + public String data; + + /** + * The original binary item content, compressed using one of the supported compression types + * (Deflate, GZip, LZMA, Uncompressed, or ZLib), and then Base64 encoded. + * + *

You can use this parameter when you're pushing a compressed binary item (such as XML/HTML, + * PDF, Word, or binary) whose size is less than 5 MB. + * + *

Whenever you're pushing an item whose size is 5 MB or more, use the + * CompressedBinaryDataFileId property instead. + * + *

If you're pushing less than 5 MB of textual (non-binary) content, you can use the data + * property instead. + * + *

See https://docs.coveo.com/en/73 for more information. + */ + public CompressedBinaryData compressedBinaryData; + + /** + * The fileId from the content that has been uploaded to the S3 via a FileContainer. The file is + * compressed using one of the supported compression types (Deflate, GZip, LZMA, Uncompressed, or + * ZLib). + * + *

You can use this parameter when you're pushing a compressed binary item (such as XML/HTML, + * PDF, Word, or binary) whose size is greater than 5 MB. + * + *

Whenever you're pushing an item whose size is less than 5 MB, use the CompressedBinaryData + * property instead. + * + *

If you're pushing less than 5 MB of textual (non-binary) content, you can use the data + * property instead. + * + *

See https://docs.coveo.com/en/73 for more information. + */ + public String compressedBinaryDataFileId; + + /** + * The file extension of the data you're pushing. + * + *

This is useful when pushing a compressed item. The converter uses this information to + * identify how to correctly process the item. + * + *

Values must include the preceding . character. + * + *

Example: `.html` + */ + public String fileExtension; + + public Document() { + this.permissions = new DocumentPermissions[] {new DocumentPermissions()}; + this.metadata = new HashMap(); + } } - diff --git a/src/main/java/com/coveo/pushapiclient/DocumentBuilder.java b/src/main/java/com/coveo/pushapiclient/DocumentBuilder.java index dd3bbd36..e4ad3385 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentBuilder.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentBuilder.java @@ -2,388 +2,397 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; -import org.apache.commons.codec.digest.DigestUtils; -import org.joda.time.DateTime; -import org.joda.time.format.ISODateTimeFormat; - import java.util.ArrayList; import java.util.Date; import java.util.Map; +import org.apache.commons.codec.digest.DigestUtils; +import org.joda.time.DateTime; +import org.joda.time.format.ISODateTimeFormat; -/** - * Utility class to build a {@link Document} - */ +/** Utility class to build a {@link Document} */ public class DocumentBuilder { - private static final ArrayList reservedKeynames = new ArrayList<>() {{ - add("compressedBinaryData"); - add("compressedBinaryDataFileId"); - add("parentId"); - add("fileExtension"); - add("data"); - add("permissions"); - add("documentId"); - add("orderingId"); - }}; - - private final Document document; - - /** - * @param uri the URI of the document. See {@link Document#uri} - * @param title the title of the document. See {@link Document#title} - */ - public DocumentBuilder(String uri, String title) { - this.document = new Document(); - this.document.uri = uri; - this.document.title = title; - } - - public Document getDocument() { - return this.document; - } - - /** - * Set the data of the document. See {@link Document#data} - * - * @param data - * @return - */ - public DocumentBuilder withData(String data) { - this.document.data = data; - return this; - } - - /** - * Set the date of the document. See {@link Document#date} - * - * @param date - * @return - */ - public DocumentBuilder withDate(String date) { - DateTime dt = DateTime.parse(date); - this.document.date = this.dateFormat(dt); - return this; - } - - /** - * Set the date of the document. See {@link Document#date} - * - * @param date - * @return - */ - public DocumentBuilder withDate(Long date) { - DateTime dt = new DateTime(date); - this.document.date = this.dateFormat(dt); - return this; - } - - /** - * Set the date of the document. See {@link Document#date} - * - * @param date - * @return - */ - public DocumentBuilder withDate(Date date) { - DateTime dt = new DateTime(date); - this.document.date = this.dateFormat(dt); - return this; - } - - /** - * Set the date of the document. See {@link Document#date} - * - * @param date - * @return - */ - public DocumentBuilder withDate(DateTime date) { - this.document.date = this.dateFormat(date); - return this; - } - - /** - * Set the modified date of the document. See {@link Document#modifiedDate} - * - * @param date - * @return - */ - public DocumentBuilder withModifiedDate(String date) { - DateTime dt = DateTime.parse(date); - this.document.modifiedDate = this.dateFormat(dt); - return this; - } - - /** - * Set the modified date of the document. See {@link Document#modifiedDate} - * - * @param date - * @return - */ - public DocumentBuilder withModifiedDate(Long date) { - DateTime dt = new DateTime(date); - this.document.modifiedDate = this.dateFormat(dt); - return this; - } - - /** - * Set the modified date of the document. See {@link Document#modifiedDate} - * - * @param date - * @return - */ - public DocumentBuilder withModifiedDate(DateTime date) { - this.document.modifiedDate = this.dateFormat(date); - return this; - } - - /** - * Set the modified date of the document. See {@link Document#modifiedDate} - * - * @param date - * @return - */ - public DocumentBuilder withModifiedDate(Date date) { - DateTime dt = new DateTime(date); - this.document.modifiedDate = this.dateFormat(dt); - return this; - } - - /** - * Set the permanentID of the document. See {@link Document#permanentId} - * - * @param permanentId - * @return - */ - public DocumentBuilder withPermanentId(String permanentId) { - this.document.permanentId = permanentId; - return this; - } - - /** - * Set the base64 encoded, compressed binary data of the document. See {@link Document#compressedBinaryData} - * - * @param compressedBinaryData - * @return - */ - public DocumentBuilder withCompressedBinaryData(CompressedBinaryData compressedBinaryData) { - this.document.compressedBinaryData = compressedBinaryData; - return this; - } - - /** - * Set the file container file ID for the compressed binary data of the document. See {@link Document#compressedBinaryDataFileId} - * - * @param compressedBinaryDataFileId - * @return - */ - public DocumentBuilder withCompressedBinaryDataFileId(String compressedBinaryDataFileId) { - this.document.compressedBinaryDataFileId = compressedBinaryDataFileId; - return this; - } - - /** - * Set the file extension on the document. See {@link Document#fileExtension} - * - * @param fileExtension - * @return - */ - public DocumentBuilder withFileExtension(String fileExtension) { - this.validateFileExtension(fileExtension); - this.document.fileExtension = fileExtension; - return this; - } - - /** - * Set the parentID on the document. See {@link Document#parentId} - * - * @param parentID - * @return - */ - public DocumentBuilder withParentID(String parentID) { - this.document.parentId = parentID; - return this; - } - - /** - * Set the clickableURI on the document. See {@link Document#clickableUri} - * - * @param clickableUri - * @return - */ - public DocumentBuilder withClickableUri(String clickableUri) { - this.document.clickableUri = clickableUri; - return this; - } - - /** - * Set the author on the document. See {@link Document#author} - * - * @param author - * @return - */ - public DocumentBuilder withAuthor(String author) { - this.document.author = author; - return this; - } - - /** - * Add a single metadata key and value pair on the document. See {@link Document#metadata} - * - * @param key - * @param metadataValue - * @return - */ - public DocumentBuilder withMetadataValue(String key, String metadataValue) { - this.setMetadataValue(key, metadataValue); - return this; - } - - /** - * Add a single metadata key and value pair on the document. See {@link Document#metadata} - * - * @param key - * @param metadataValue - * @return - */ - public DocumentBuilder withMetadataValue(String key, String[] metadataValue) { - this.setMetadataValue(key, metadataValue); - return this; - } - - /** - * Add a single metadata key and value pair on the document. See {@link Document#metadata} - * - * @param key - * @param metadataValue - * @return - */ - public DocumentBuilder withMetadataValue(String key, Integer metadataValue) { - this.setMetadataValue(key, metadataValue); - return this; - } - - /** - * Add a single metadata key and value pair on the document. See {@link Document#metadata} - * - * @param key - * @param metadataValue - * @return - */ - public DocumentBuilder withMetadataValue(String key, Integer[] metadataValue) { - this.setMetadataValue(key, metadataValue); - return this; - } - - /** - * Set metadata on the document. See {@link Document#metadata} - * - * @param metadata - * @return - */ - public DocumentBuilder withMetadata(Map metadata) { - metadata.forEach(this::setMetadataValue); - return this; - } - - /** - * Set allowed identities on the document. See {@link Document#permissions} - * - * @param allowedPermissions - * @return - */ - public DocumentBuilder withAllowedPermissions(SecurityIdentityBuilder allowedPermissions) { - this.document.permissions[0].allowedPermissions = allowedPermissions.build(); - return this; - } - - /** - * Set denied identities on the document. See {@link Document#permissions} - * - * @param deniedPermissions - * @return - */ - public DocumentBuilder withDeniedPermissions(SecurityIdentityBuilder deniedPermissions) { - this.document.permissions[0].deniedPermissions = deniedPermissions.build(); - return this; - } - - /** - * Set allowAnonymous for permissions on the document. See {@link Document#permissions} - * - * @param allowAnonymous - * @return - */ - public DocumentBuilder withAllowAnonymousUsers(Boolean allowAnonymous) { - this.document.permissions[0].allowAnonymous = allowAnonymous; - return this; - } - - /** - * Set the fully built out DocumentPermissions array. See {@Link Document#permissions} - * @param documentPermissions - * @return - */ - public DocumentBuilder withDocumentPermissions(DocumentPermissions[] documentPermissions) { - this.document.permissions = documentPermissions; - return this; - } - - /** - * Marshal the document into a JSON string accepted by the push API. - * - * @return - */ - public String marshal() { - return this.marshalJsonObject().toString(); - } - - /** - * Marshal the document into a JSON object accepted by the push API. - * - * @return - */ - public JsonObject marshalJsonObject() { - this.generatePermanentId(); - - JsonObject jsonDocument = new Gson().toJsonTree(this.document).getAsJsonObject(); - this.document.metadata.forEach((key, value) -> { - jsonDocument.add(key, new Gson().toJsonTree(value)); - }); - jsonDocument.remove("metadata"); - - if (this.document.compressedBinaryData != null) { - jsonDocument.addProperty("compressedBinaryData", this.document.compressedBinaryData.getData()); + private static final ArrayList reservedKeynames = + new ArrayList<>() { + { + add("compressedBinaryData"); + add("compressedBinaryDataFileId"); + add("parentId"); + add("fileExtension"); + add("data"); + add("permissions"); + add("documentId"); + add("orderingId"); } + }; + + private final Document document; + + /** + * @param uri the URI of the document. See {@link Document#uri} + * @param title the title of the document. See {@link Document#title} + */ + public DocumentBuilder(String uri, String title) { + this.document = new Document(); + this.document.uri = uri; + this.document.title = title; + } + + public Document getDocument() { + return this.document; + } + + /** + * Set the data of the document. See {@link Document#data} + * + * @param data + * @return + */ + public DocumentBuilder withData(String data) { + this.document.data = data; + return this; + } + + /** + * Set the date of the document. See {@link Document#date} + * + * @param date + * @return + */ + public DocumentBuilder withDate(String date) { + DateTime dt = DateTime.parse(date); + this.document.date = this.dateFormat(dt); + return this; + } + + /** + * Set the date of the document. See {@link Document#date} + * + * @param date + * @return + */ + public DocumentBuilder withDate(Long date) { + DateTime dt = new DateTime(date); + this.document.date = this.dateFormat(dt); + return this; + } + + /** + * Set the date of the document. See {@link Document#date} + * + * @param date + * @return + */ + public DocumentBuilder withDate(Date date) { + DateTime dt = new DateTime(date); + this.document.date = this.dateFormat(dt); + return this; + } + + /** + * Set the date of the document. See {@link Document#date} + * + * @param date + * @return + */ + public DocumentBuilder withDate(DateTime date) { + this.document.date = this.dateFormat(date); + return this; + } + + /** + * Set the modified date of the document. See {@link Document#modifiedDate} + * + * @param date + * @return + */ + public DocumentBuilder withModifiedDate(String date) { + DateTime dt = DateTime.parse(date); + this.document.modifiedDate = this.dateFormat(dt); + return this; + } + + /** + * Set the modified date of the document. See {@link Document#modifiedDate} + * + * @param date + * @return + */ + public DocumentBuilder withModifiedDate(Long date) { + DateTime dt = new DateTime(date); + this.document.modifiedDate = this.dateFormat(dt); + return this; + } + + /** + * Set the modified date of the document. See {@link Document#modifiedDate} + * + * @param date + * @return + */ + public DocumentBuilder withModifiedDate(DateTime date) { + this.document.modifiedDate = this.dateFormat(date); + return this; + } + + /** + * Set the modified date of the document. See {@link Document#modifiedDate} + * + * @param date + * @return + */ + public DocumentBuilder withModifiedDate(Date date) { + DateTime dt = new DateTime(date); + this.document.modifiedDate = this.dateFormat(dt); + return this; + } + + /** + * Set the permanentID of the document. See {@link Document#permanentId} + * + * @param permanentId + * @return + */ + public DocumentBuilder withPermanentId(String permanentId) { + this.document.permanentId = permanentId; + return this; + } + + /** + * Set the base64 encoded, compressed binary data of the document. See {@link + * Document#compressedBinaryData} + * + * @param compressedBinaryData + * @return + */ + public DocumentBuilder withCompressedBinaryData(CompressedBinaryData compressedBinaryData) { + this.document.compressedBinaryData = compressedBinaryData; + return this; + } + + /** + * Set the file container file ID for the compressed binary data of the document. See {@link + * Document#compressedBinaryDataFileId} + * + * @param compressedBinaryDataFileId + * @return + */ + public DocumentBuilder withCompressedBinaryDataFileId(String compressedBinaryDataFileId) { + this.document.compressedBinaryDataFileId = compressedBinaryDataFileId; + return this; + } + + /** + * Set the file extension on the document. See {@link Document#fileExtension} + * + * @param fileExtension + * @return + */ + public DocumentBuilder withFileExtension(String fileExtension) { + this.validateFileExtension(fileExtension); + this.document.fileExtension = fileExtension; + return this; + } + + /** + * Set the parentID on the document. See {@link Document#parentId} + * + * @param parentID + * @return + */ + public DocumentBuilder withParentID(String parentID) { + this.document.parentId = parentID; + return this; + } + + /** + * Set the clickableURI on the document. See {@link Document#clickableUri} + * + * @param clickableUri + * @return + */ + public DocumentBuilder withClickableUri(String clickableUri) { + this.document.clickableUri = clickableUri; + return this; + } + + /** + * Set the author on the document. See {@link Document#author} + * + * @param author + * @return + */ + public DocumentBuilder withAuthor(String author) { + this.document.author = author; + return this; + } + + /** + * Add a single metadata key and value pair on the document. See {@link Document#metadata} + * + * @param key + * @param metadataValue + * @return + */ + public DocumentBuilder withMetadataValue(String key, String metadataValue) { + this.setMetadataValue(key, metadataValue); + return this; + } + + /** + * Add a single metadata key and value pair on the document. See {@link Document#metadata} + * + * @param key + * @param metadataValue + * @return + */ + public DocumentBuilder withMetadataValue(String key, String[] metadataValue) { + this.setMetadataValue(key, metadataValue); + return this; + } + + /** + * Add a single metadata key and value pair on the document. See {@link Document#metadata} + * + * @param key + * @param metadataValue + * @return + */ + public DocumentBuilder withMetadataValue(String key, Integer metadataValue) { + this.setMetadataValue(key, metadataValue); + return this; + } + + /** + * Add a single metadata key and value pair on the document. See {@link Document#metadata} + * + * @param key + * @param metadataValue + * @return + */ + public DocumentBuilder withMetadataValue(String key, Integer[] metadataValue) { + this.setMetadataValue(key, metadataValue); + return this; + } + + /** + * Set metadata on the document. See {@link Document#metadata} + * + * @param metadata + * @return + */ + public DocumentBuilder withMetadata(Map metadata) { + metadata.forEach(this::setMetadataValue); + return this; + } + + /** + * Set allowed identities on the document. See {@link Document#permissions} + * + * @param allowedPermissions + * @return + */ + public DocumentBuilder withAllowedPermissions(SecurityIdentityBuilder allowedPermissions) { + this.document.permissions[0].allowedPermissions = allowedPermissions.build(); + return this; + } + + /** + * Set denied identities on the document. See {@link Document#permissions} + * + * @param deniedPermissions + * @return + */ + public DocumentBuilder withDeniedPermissions(SecurityIdentityBuilder deniedPermissions) { + this.document.permissions[0].deniedPermissions = deniedPermissions.build(); + return this; + } + + /** + * Set allowAnonymous for permissions on the document. See {@link Document#permissions} + * + * @param allowAnonymous + * @return + */ + public DocumentBuilder withAllowAnonymousUsers(Boolean allowAnonymous) { + this.document.permissions[0].allowAnonymous = allowAnonymous; + return this; + } + + /** + * Set the fully built out DocumentPermissions array. See {@Link Document#permissions} + * + * @param documentPermissions + * @return + */ + public DocumentBuilder withDocumentPermissions(DocumentPermissions[] documentPermissions) { + this.document.permissions = documentPermissions; + return this; + } + + /** + * Marshal the document into a JSON string accepted by the push API. + * + * @return + */ + public String marshal() { + return this.marshalJsonObject().toString(); + } + + /** + * Marshal the document into a JSON object accepted by the push API. + * + * @return + */ + public JsonObject marshalJsonObject() { + this.generatePermanentId(); + + JsonObject jsonDocument = new Gson().toJsonTree(this.document).getAsJsonObject(); + this.document.metadata.forEach( + (key, value) -> { + jsonDocument.add(key, new Gson().toJsonTree(value)); + }); + jsonDocument.remove("metadata"); - jsonDocument.addProperty("documentId", this.document.uri); - return jsonDocument; + if (this.document.compressedBinaryData != null) { + jsonDocument.addProperty( + "compressedBinaryData", this.document.compressedBinaryData.getData()); } - private String dateFormat(DateTime dt) { - return dt.toString(ISODateTimeFormat.dateTime()); - } + jsonDocument.addProperty("documentId", this.document.uri); + return jsonDocument; + } - private void setMetadataValue(String key, Object metadataValue) { - this.validateReservedMetadataKeyNames(key); - this.document.metadata.put(key, metadataValue); - } + private String dateFormat(DateTime dt) { + return dt.toString(ISODateTimeFormat.dateTime()); + } - private void validateFileExtension(String fileExtension) { - if (!fileExtension.startsWith(".")) { - throw new RuntimeException(String.format("%s is not a valid file extension. It should start with a leading .")); - } + private void setMetadataValue(String key, Object metadataValue) { + this.validateReservedMetadataKeyNames(key); + this.document.metadata.put(key, metadataValue); + } + + private void validateFileExtension(String fileExtension) { + if (!fileExtension.startsWith(".")) { + throw new RuntimeException( + String.format("%s is not a valid file extension. It should start with a leading .")); } + } - private void validateReservedMetadataKeyNames(String key) { - if (reservedKeynames.contains(key)) { - throw new RuntimeException(String.format("Cannot use %s as a metadata key: It is a reserved keynames. See https://docs.coveo.com/en/78/index-content/push-api-reference#json-document-reserved-key-names", key)); - } + private void validateReservedMetadataKeyNames(String key) { + if (reservedKeynames.contains(key)) { + throw new RuntimeException( + String.format( + "Cannot use %s as a metadata key: It is a reserved keynames. See https://docs.coveo.com/en/78/index-content/push-api-reference#json-document-reserved-key-names", + key)); } + } - private void generatePermanentId() { - if (this.document.permanentId == null) { - String md5 = DigestUtils.md5Hex(this.document.uri); - String sha1 = DigestUtils.sha1Hex(this.document.uri); - this.document.permanentId = md5.substring(0, 30) + sha1.substring(0, 30); - } + private void generatePermanentId() { + if (this.document.permanentId == null) { + String md5 = DigestUtils.md5Hex(this.document.uri); + String sha1 = DigestUtils.sha1Hex(this.document.uri); + this.document.permanentId = md5.substring(0, 30) + sha1.substring(0, 30); } + } } diff --git a/src/main/java/com/coveo/pushapiclient/DocumentPermissions.java b/src/main/java/com/coveo/pushapiclient/DocumentPermissions.java index 63a1c5c3..4cb5fc68 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentPermissions.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentPermissions.java @@ -1,23 +1,18 @@ package com.coveo.pushapiclient; public class DocumentPermissions { - /** - * Whether to allow anonymous users in this permission set. - * Default value is false. - */ - public boolean allowAnonymous; - /** - * The list of allowed permissions for this permission set. - */ - public SecurityIdentity[] allowedPermissions; - /** - * The list of denied permissions for this permission set. - */ - public SecurityIdentity[] deniedPermissions; + /** Whether to allow anonymous users in this permission set. Default value is false. */ + public boolean allowAnonymous; - public DocumentPermissions() { - this.allowAnonymous = true; - this.allowedPermissions = new SecurityIdentity[]{}; - this.deniedPermissions = new SecurityIdentity[]{}; - } + /** The list of allowed permissions for this permission set. */ + public SecurityIdentity[] allowedPermissions; + + /** The list of denied permissions for this permission set. */ + public SecurityIdentity[] deniedPermissions; + + public DocumentPermissions() { + this.allowAnonymous = true; + this.allowedPermissions = new SecurityIdentity[] {}; + this.deniedPermissions = new SecurityIdentity[] {}; + } } diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index 66355664..bd83a2bc 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -3,99 +3,93 @@ import java.io.IOException; import java.util.ArrayList; -/** - * Represents a queue for uploading documents using a specified upload strategy - */ +/** Represents a queue for uploading documents using a specified upload strategy */ class DocumentUploadQueue { - private final UploadStrategy uploader; - private final int maxQueueSize = 5 * 1024 * 1024; - private ArrayList documentToAddList; - private ArrayList documentToDeleteList; - private int size; + private final UploadStrategy uploader; + private final int maxQueueSize = 5 * 1024 * 1024; + private ArrayList documentToAddList; + private ArrayList documentToDeleteList; + private int size; - /** - * Constructs a new DocumentUploadQueue object with a default maximum queue size - * limit of 5MB. - * - * @param uploader The upload strategy to be used for document uploads. - */ - public DocumentUploadQueue(UploadStrategy uploader) { - this.documentToAddList = new ArrayList<>(); - this.documentToDeleteList = new ArrayList<>(); - this.uploader = uploader; - } + /** + * Constructs a new DocumentUploadQueue object with a default maximum queue size limit of 5MB. + * + * @param uploader The upload strategy to be used for document uploads. + */ + public DocumentUploadQueue(UploadStrategy uploader) { + this.documentToAddList = new ArrayList<>(); + this.documentToDeleteList = new ArrayList<>(); + this.uploader = uploader; + } - /** - * Flushes the accumulated documents by applying the upload strategy. - * - * @throws IOException If an I/O error occurs during the upload. - * @throws InterruptedException If the upload process is interrupted. - */ - public void flush() throws IOException, InterruptedException { - if (this.isEmpty()) { - return; - } - BatchUpdate batch = this.getBatch(); - // TODO: LENS-871: support concurrent requests - this.uploader.apply(batch); - this.size = 0; - this.documentToAddList.clear(); - this.documentToDeleteList.clear(); + /** + * Flushes the accumulated documents by applying the upload strategy. + * + * @throws IOException If an I/O error occurs during the upload. + * @throws InterruptedException If the upload process is interrupted. + */ + public void flush() throws IOException, InterruptedException { + if (this.isEmpty()) { + return; } + BatchUpdate batch = this.getBatch(); + // TODO: LENS-871: support concurrent requests + this.uploader.apply(batch); + this.size = 0; + this.documentToAddList.clear(); + this.documentToDeleteList.clear(); + } - /** - * Adds a {@link DocumentBuilder} to the upload queue and flushes the queue if - * it exceeds the maximum content length. - * See {@link DocumentUploadQueue#flush}. - * - * @param document The document to be added to the index. - * @throws IOException If an I/O error occurs during the upload. - * @throws InterruptedException If the upload process is interrupted. - */ - public void add(DocumentBuilder document) throws IOException, InterruptedException { - if (document == null) { - return; - } - - final int sizeOfDoc = document.marshal().getBytes().length; - if (this.size + sizeOfDoc >= this.maxQueueSize) { - this.flush(); - } - documentToAddList.add(document); - this.size += sizeOfDoc; + /** + * Adds a {@link DocumentBuilder} to the upload queue and flushes the queue if it exceeds the + * maximum content length. See {@link DocumentUploadQueue#flush}. + * + * @param document The document to be added to the index. + * @throws IOException If an I/O error occurs during the upload. + * @throws InterruptedException If the upload process is interrupted. + */ + public void add(DocumentBuilder document) throws IOException, InterruptedException { + if (document == null) { + return; } - /** - * Adds the {@link DeleteDocument} to the upload queue and flushes the queue if - * it exceeds the maximum content length. - * See {@link DocumentUploadQueue#flush}. - * - * @param document The document to be deleted from the index. - * @throws IOException If an I/O error occurs during the upload. - * @throws InterruptedException If the upload process is interrupted. - */ - public void add(DeleteDocument document) throws IOException, InterruptedException { - if (document == null) { - return; - } - - final int sizeOfDoc = document.marshalJsonObject().toString().getBytes().length; - if (this.size + sizeOfDoc >= this.maxQueueSize) { - this.flush(); - } - documentToDeleteList.add(document); - this.size += sizeOfDoc; + final int sizeOfDoc = document.marshal().getBytes().length; + if (this.size + sizeOfDoc >= this.maxQueueSize) { + this.flush(); } + documentToAddList.add(document); + this.size += sizeOfDoc; + } - public BatchUpdate getBatch() { - return new BatchUpdate( - new ArrayList(this.documentToAddList), - new ArrayList(this.documentToDeleteList)); + /** + * Adds the {@link DeleteDocument} to the upload queue and flushes the queue if it exceeds the + * maximum content length. See {@link DocumentUploadQueue#flush}. + * + * @param document The document to be deleted from the index. + * @throws IOException If an I/O error occurs during the upload. + * @throws InterruptedException If the upload process is interrupted. + */ + public void add(DeleteDocument document) throws IOException, InterruptedException { + if (document == null) { + return; } - public boolean isEmpty() { - // TODO: LENS-843: include partial document updates - return documentToAddList.isEmpty() && documentToDeleteList.isEmpty(); + final int sizeOfDoc = document.marshalJsonObject().toString().getBytes().length; + if (this.size + sizeOfDoc >= this.maxQueueSize) { + this.flush(); } + documentToDeleteList.add(document); + this.size += sizeOfDoc; + } + + public BatchUpdate getBatch() { + return new BatchUpdate( + new ArrayList(this.documentToAddList), + new ArrayList(this.documentToDeleteList)); + } + public boolean isEmpty() { + // TODO: LENS-843: include partial document updates + return documentToAddList.isEmpty() && documentToDeleteList.isEmpty(); + } } diff --git a/src/main/java/com/coveo/pushapiclient/Environment.java b/src/main/java/com/coveo/pushapiclient/Environment.java index b42e0176..fb175c7f 100644 --- a/src/main/java/com/coveo/pushapiclient/Environment.java +++ b/src/main/java/com/coveo/pushapiclient/Environment.java @@ -1,21 +1,19 @@ package com.coveo.pushapiclient; -/** - * Available environments to use as the host for the PushAPI. - */ +/** Available environments to use as the host for the PushAPI. */ public enum Environment { - PRODUCTION( "prod"), - HIPAA("hipaa"), - DEVELOPMENT("dev"), - STAGING("stg"); + PRODUCTION("prod"), + HIPAA("hipaa"), + DEVELOPMENT("dev"), + STAGING("stg"); - private String value; + private String value; - Environment(String value) { - this.value = value; - } + Environment(String value) { + this.value = value; + } - public String getValue() { - return this.value; - } + public String getValue() { + return this.value; + } } diff --git a/src/main/java/com/coveo/pushapiclient/FileContainer.java b/src/main/java/com/coveo/pushapiclient/FileContainer.java index 2d67b8db..57920c7b 100644 --- a/src/main/java/com/coveo/pushapiclient/FileContainer.java +++ b/src/main/java/com/coveo/pushapiclient/FileContainer.java @@ -2,11 +2,9 @@ import java.util.Map; -/** - * See [Creating a FileContainer](https://docs.coveo.com/en/43) - */ +/** See [Creating a FileContainer](https://docs.coveo.com/en/43) */ public class FileContainer { - public String uploadUri; - public String fileId; - public Map requiredHeaders; + public String uploadUri; + public String fileId; + public Map requiredHeaders; } diff --git a/src/main/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilder.java b/src/main/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilder.java index 6a2077a0..0beb6dc7 100644 --- a/src/main/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilder.java +++ b/src/main/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilder.java @@ -5,63 +5,70 @@ /** * Build a security identity of type `GROUP`. - *

- * Typically used in conjunction with {@link DocumentBuilder#withAllowedPermissions} or {@link DocumentBuilder#withDeniedPermissions}. - *

- * See {@link SecurityIdentity}. + * + *

Typically used in conjunction with {@link DocumentBuilder#withAllowedPermissions} or {@link + * DocumentBuilder#withDeniedPermissions}. + * + *

See {@link SecurityIdentity}. */ public class GroupSecurityIdentityBuilder implements SecurityIdentityBuilder { - private final String[] identities; - private final String securityProvider; + private final String[] identities; + private final String securityProvider; - public GroupSecurityIdentityBuilder(String[] identities, String securityProvider) { - this.identities = identities; - this.securityProvider = securityProvider; - } + public GroupSecurityIdentityBuilder(String[] identities, String securityProvider) { + this.identities = identities; + this.securityProvider = securityProvider; + } - /** - * Construct a GroupSecurityIdentityBuilder with a single identity - * - * @param identity - * @param securityProvider - */ - public GroupSecurityIdentityBuilder(String identity, String securityProvider) { - this(new String[]{identity}, securityProvider); - } + /** + * Construct a GroupSecurityIdentityBuilder with a single identity + * + * @param identity + * @param securityProvider + */ + public GroupSecurityIdentityBuilder(String identity, String securityProvider) { + this(new String[] {identity}, securityProvider); + } - public SecurityIdentity[] build() { - return new AnySecurityIdentityBuilder(this.identities, SecurityIdentityType.GROUP, this.securityProvider).build(); - } + public SecurityIdentity[] build() { + return new AnySecurityIdentityBuilder( + this.identities, SecurityIdentityType.GROUP, this.securityProvider) + .build(); + } - public String[] getIdentities() { - return identities; - } + public String[] getIdentities() { + return identities; + } - public String getSecurityProvider() { - return securityProvider; - } + public String getSecurityProvider() { + return securityProvider; + } - @Override - public String toString() { - return "GroupSecurityIdentityBuilder[" + - "identities=" + Arrays.toString(identities) + - ", securityProvider='" + securityProvider + '\'' + - ']'; - } + @Override + public String toString() { + return "GroupSecurityIdentityBuilder[" + + "identities=" + + Arrays.toString(identities) + + ", securityProvider='" + + securityProvider + + '\'' + + ']'; + } - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - GroupSecurityIdentityBuilder that = (GroupSecurityIdentityBuilder) obj; - return Arrays.equals(identities, that.identities) && Objects.equals(securityProvider, that.securityProvider); - } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + GroupSecurityIdentityBuilder that = (GroupSecurityIdentityBuilder) obj; + return Arrays.equals(identities, that.identities) + && Objects.equals(securityProvider, that.securityProvider); + } - @Override - public int hashCode() { - int result = Objects.hash(securityProvider); - result = 31 * result + Arrays.hashCode(identities); - return result; - } + @Override + public int hashCode() { + int result = Objects.hash(securityProvider); + result = 31 * result + Arrays.hashCode(identities); + return result; + } } diff --git a/src/main/java/com/coveo/pushapiclient/IdentityModel.java b/src/main/java/com/coveo/pushapiclient/IdentityModel.java index 35ec0ddd..42eebd88 100644 --- a/src/main/java/com/coveo/pushapiclient/IdentityModel.java +++ b/src/main/java/com/coveo/pushapiclient/IdentityModel.java @@ -3,13 +3,13 @@ import java.util.Map; public class IdentityModel { - public final Map additionalInfo; - public final String name; - public final SecurityIdentityType type; + public final Map additionalInfo; + public final String name; + public final SecurityIdentityType type; - public IdentityModel(String name, SecurityIdentityType type, Map additionalInfo) { - this.name = name; - this.type = type; - this.additionalInfo = additionalInfo; - } + public IdentityModel(String name, SecurityIdentityType type, Map additionalInfo) { + this.name = name; + this.type = type; + this.additionalInfo = additionalInfo; + } } diff --git a/src/main/java/com/coveo/pushapiclient/PlatformClient.java b/src/main/java/com/coveo/pushapiclient/PlatformClient.java index aa5e2035..ba28dc78 100644 --- a/src/main/java/com/coveo/pushapiclient/PlatformClient.java +++ b/src/main/java/com/coveo/pushapiclient/PlatformClient.java @@ -2,7 +2,6 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; - import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; @@ -12,489 +11,583 @@ import java.util.HashMap; import java.util.stream.Stream; -/** - * PlatformClient handles network requests to the Coveo platform - */ +/** PlatformClient handles network requests to the Coveo platform */ public class PlatformClient { - private final String apiKey; - private final String organizationId; - private final HttpClient httpClient; - private final PlatformUrl platformUrl; - - /** - * Construct a PlatformClient - * - * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo organization. See [Manage API Keys](https://docs.coveo.com/en/1718). - * @param organizationId The Coveo Organization identifier. - */ - public PlatformClient(String apiKey, String organizationId) { - this(apiKey, organizationId, new PlatformUrlBuilder().build()); - } - - /** - * Construct a PlatformClient - * - * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo organization. See [Manage API Keys](https://docs.coveo.com/en/1718). - * @param organizationId The Coveo Organization identifier. - * @param platformUrl The PlatformUrl. - */ - public PlatformClient(String apiKey, String organizationId, PlatformUrl platformUrl) { - this.apiKey = apiKey; - this.organizationId = organizationId; - this.httpClient = HttpClient.newHttpClient(); - this.platformUrl = platformUrl; - } - - /** - * Construct a PlatformClient - * - * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo organization. See [Manage API Keys](https://docs.coveo.com/en/1718). - * @param organizationId The Coveo Organization identifier. - * @param httpClient The HttpClient. - */ - public PlatformClient(String apiKey, String organizationId, HttpClient httpClient) { - this.apiKey = apiKey; - this.organizationId = organizationId; - this.httpClient = httpClient; - this.platformUrl = new PlatformUrlBuilder().build(); - } - - - /** - * @deprecated Please now use PlatformUrl to define your Platform environment - * @see PlatformUrl Construct a PlatformUrl - * - * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo organization. See [Manage API Keys](https://docs.coveo.com/en/1718). - * @param organizationId The Coveo Organization identifier. - * @param environment The Environment to be used. - */ - @Deprecated - public PlatformClient(String apiKey, String organizationId, Environment environment) { - this.apiKey = apiKey; - this.organizationId = organizationId; - this.httpClient = HttpClient.newHttpClient(); - this.platformUrl = new PlatformUrlBuilder() - .withEnvironment(environment) - .build(); - } - - /** - * Create a new push source - * @deprecated - * Please use {@link PlatformClient#createSource(String, SourceType, SourceVisibility)} instead - * - * @param name - * @param sourceVisibility - * @return - * @throws IOException - * @throws InterruptedException - */ - @Deprecated - public HttpResponse createSource(String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { - return createSource(name,SourceType.PUSH,sourceVisibility); - } - - /** - * Create a new source - * - * @param name The name of the source to create - * @param sourceType The type of the source to create - * @param sourceVisibility The security option that should be applied to the content of the source. See [Content Security](https://docs.coveo.com/en/1779). - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createSource(String name, final SourceType sourceType, SourceVisibility sourceVisibility) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - - String json = this.toJSON(new HashMap<>() {{ - put("sourceType", sourceType.toString()); - put("pushEnabled", sourceType.isPushEnabled()); - put("streamEnabled", sourceType.isStreamEnabled()); - put("name", name); - put("sourceVisibility", sourceVisibility); - }}); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .POST(HttpRequest.BodyPublishers.ofString(json)) - .uri(URI.create(this.getBaseSourceURL())) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Create or update a security identity. See [Adding a Single Security Identity](https://docs.coveo.com/en/167) and [Security Identity Models](https://docs.coveo.com/en/139). - * - * @param securityProviderId - * @param securityIdentityModel - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createOrUpdateSecurityIdentity(String securityProviderId, SecurityIdentityModel securityIdentityModel) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + "/permissions"); - - String json = new Gson().toJson(securityIdentityModel); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .PUT(HttpRequest.BodyPublishers.ofString(json)) - .uri(uri) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Create or update a security identity alias. See [Adding a Single Alias](https://docs.coveo.com/en/142) and [User Alias Definition Examples](https://docs.coveo.com/en/46). - * - * @param securityProviderId - * @param securityIdentityAlias - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createOrUpdateSecurityIdentityAlias(String securityProviderId, SecurityIdentityAliasModel securityIdentityAlias) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + "/mappings"); - - String json = new Gson().toJson(securityIdentityAlias); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .PUT(HttpRequest.BodyPublishers.ofString(json)) - .uri(uri) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Delete a security identity. See [Disabling a Single Security Identity](https://docs.coveo.com/en/84). - * - * @param securityProviderId - * @param securityIdentityToDelete - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteSecurityIdentity(String securityProviderId, SecurityIdentityDelete securityIdentityToDelete) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + "/permissions"); - - String json = new Gson().toJson(securityIdentityToDelete); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .method("DELETE", HttpRequest.BodyPublishers.ofString(json)) - .uri(uri) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Delete old security identities. See [Disabling Old Security Identities](https://docs.coveo.com/en/33). - * - * @param securityProviderId - * @param batchDelete - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteOldSecurityIdentities(String securityProviderId, SecurityIdentityDeleteOptions batchDelete) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + String.format("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/permissions/olderthan?queueDelay=%s%s", batchDelete.getQueueDelay(), appendOrderingId(batchDelete.getOrderingId()))); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .DELETE() - .uri(uri) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Returns the orderingId for the query string only when a valid orderingId is available. - * - * @param orderingId - * @return - */ - public String appendOrderingId(long orderingId) { - if (orderingId > 0) { - return String.format("&orderingId=%s", orderingId); - } - return ""; - } - - /** - * Manage batches of security identities. See [Manage Batches of Security Identities](https://docs.coveo.com/en/55). - * - * @param securityProviderId - * @param batchConfig - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse manageSecurityIdentities(String securityProviderId, SecurityIdentityBatchConfig batchConfig) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + String.format("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/permissions/batch?fileId=%s%s", batchConfig.getFileId(), appendOrderingId(batchConfig.getOrderingId()))); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .PUT(HttpRequest.BodyPublishers.noBody()) - .uri(uri) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Adds or updates an individual item in a push source. See [Adding a Single Item in a Push Source](https://docs.coveo.com/en/133). - * - * @param sourceId - * @param documentJSON - * @param documentId - * @param compressionType - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse pushDocument(String sourceId, String documentJSON, String documentId, CompressionType compressionType) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/documents?documentId=%s&compressionType=%s", sourceId, documentId, compressionType.toString())); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .PUT(HttpRequest.BodyPublishers.ofString(documentJSON)) - .uri(uri) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Deletes a specific item from a Push source. Optionally, the child items of that item can also be deleted. See [Deleting an Item in a Push Source](https://docs.coveo.com/en/171). - * - * @param sourceId - * @param documentId - * @param deleteChildren - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteDocument(String sourceId, String documentId, Boolean deleteChildren) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/documents?documentId=%s&deleteChildren=%s", sourceId, documentId, deleteChildren)); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .DELETE() - .uri(uri) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - public HttpResponse openStream(String sourceId) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - // TODO: LENS-875: standardize string manipulation - URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/stream/open", sourceId)); - - // TODO: LENS-876: reduce code duplication - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .POST(HttpRequest.BodyPublishers.ofString("")) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - public HttpResponse closeStream(String sourceId, String streamId) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/stream/%s/close", sourceId, streamId)); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .POST(HttpRequest.BodyPublishers.ofString("")) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - public HttpResponse requireStreamChunk(String sourceId, String streamId) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/stream/%s/chunk", sourceId, streamId)); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .POST(HttpRequest.BodyPublishers.ofString("")) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Create a file container. See [Creating a File Container](https://docs.coveo.com/en/43). - * - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createFileContainer() throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBasePushURL() + "/files"); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .POST(HttpRequest.BodyPublishers.ofString("")) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Update the status of a Push source. See [Updating the Status of a Push Source](https://docs.coveo.com/en/35). - * - * @param status - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse updateSourceStatus(String sourceId, PushAPIStatus status) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/status?statusType=%s", sourceId, status.toString())); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .POST(HttpRequest.BodyPublishers.ofString("")) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Upload content update into a file container. See [Upload the Content Update into the File Container](https://docs.coveo.com/en/90/index-content/manage-batches-of-items-in-a-push-source#step-2-upload-the-content-update-into-the-file-container). - * - * @param fileContainer - * @param batchUpdateJson - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse uploadContentToFileContainer(FileContainer fileContainer, String batchUpdateJson) throws IOException, InterruptedException { - String[] headers = fileContainer.requiredHeaders.entrySet() - .stream() - .flatMap(entry -> Stream.of(entry.getKey(), entry.getValue())) - .toArray(String[]::new); - URI uri = URI.create(fileContainer.uploadUri); - - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .PUT(HttpRequest.BodyPublishers.ofString(batchUpdateJson)) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Push a file container into a push source. See [Push the File Container into a Push Source](https://docs.coveo.com/en/90/index-content/manage-batches-of-items-in-a-push-source#step-3-push-the-file-container-into-a-push-source). - * - * @param sourceId - * @param fileContainer - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse pushFileContainerContent(String sourceId, FileContainer fileContainer) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); - URI uri = URI.create(this.getBasePushURL() + String.format("/sources/%s/documents/batch?fileId=%s", sourceId, fileContainer.fileId)); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .PUT(HttpRequest.BodyPublishers.ofString("")) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - /** - * Push a binary to a File Container. See [Upload the Item Data Into the File Container](https://docs.coveo.com/en/69#step-2-upload-the-item-data-into-the-file-container) - * - * @param fileContainer - * @param fileAsBytes - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse pushBinaryToFileContainer(FileContainer fileContainer, byte[] fileAsBytes) throws IOException, InterruptedException { - String[] headers = this.getHeaders(this.getAes256Header(), this.getContentTypeApplicationOctetStreamHeader()); - URI uri = URI.create(fileContainer.uploadUri); - - HttpRequest request = HttpRequest.newBuilder() - .headers(headers) - .uri(uri) - .PUT(HttpRequest.BodyPublishers.ofByteArray(fileAsBytes)) - .build(); - - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - } - - private String getBaseSourceURL() { - return String.format("%s/sources", this.getBasePlatformURL()); - } - - private String getBasePlatformURL() { - return String.format("%s/rest/organizations/%s", this.platformUrl.getPlatformUrl(),this.organizationId); - } - - private String getBasePushURL() { - return String.format("%s/push/v1/organizations/%s", this.platformUrl.getApiUrl(), this.organizationId); - } - - private String getBaseProviderURL(String providerId) { - return String.format("%s/providers/%s", this.getBasePushURL(), providerId); - } - - private String[] getHeaders(String[]... headers) { - String[] out = new String[]{}; - for (String[] header : headers) { - out = Stream.concat(Arrays.stream(out), Arrays.stream(header)) - .toArray(String[]::new); - } - return out; - } - - private String[] getAuthorizationHeader() { - return new String[]{"Authorization", String.format("Bearer %s", this.apiKey)}; - } - - private String[] getContentTypeApplicationJSONHeader() { - return new String[]{"Content-Type", "application/json", "Accept", "application/json"}; - } - - private String[] getAes256Header() { - return new String[]{"x-amz-server-side-encryption", "AES256"}; - } - - private String[] getContentTypeApplicationOctetStreamHeader() { - return new String[]{"Content-Type", "application/octet-stream"}; - } - - private String toJSON(HashMap hashMap) { - return new Gson().toJson(hashMap, new TypeToken>() { - }.getType()); - } + private final String apiKey; + private final String organizationId; + private final HttpClient httpClient; + private final PlatformUrl platformUrl; + + /** + * Construct a PlatformClient + * + * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo + * organization. See [Manage API Keys](https://docs.coveo.com/en/1718). + * @param organizationId The Coveo Organization identifier. + */ + public PlatformClient(String apiKey, String organizationId) { + this(apiKey, organizationId, new PlatformUrlBuilder().build()); + } + + /** + * Construct a PlatformClient + * + * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo + * organization. See [Manage API Keys](https://docs.coveo.com/en/1718). + * @param organizationId The Coveo Organization identifier. + * @param platformUrl The PlatformUrl. + */ + public PlatformClient(String apiKey, String organizationId, PlatformUrl platformUrl) { + this.apiKey = apiKey; + this.organizationId = organizationId; + this.httpClient = HttpClient.newHttpClient(); + this.platformUrl = platformUrl; + } + + /** + * Construct a PlatformClient + * + * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo + * organization. See [Manage API Keys](https://docs.coveo.com/en/1718). + * @param organizationId The Coveo Organization identifier. + * @param httpClient The HttpClient. + */ + public PlatformClient(String apiKey, String organizationId, HttpClient httpClient) { + this.apiKey = apiKey; + this.organizationId = organizationId; + this.httpClient = httpClient; + this.platformUrl = new PlatformUrlBuilder().build(); + } + + /** + * @deprecated Please now use PlatformUrl to define your Platform environment + * @see PlatformUrl Construct a PlatformUrl + * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo + * organization. See [Manage API Keys](https://docs.coveo.com/en/1718). + * @param organizationId The Coveo Organization identifier. + * @param environment The Environment to be used. + */ + @Deprecated + public PlatformClient(String apiKey, String organizationId, Environment environment) { + this.apiKey = apiKey; + this.organizationId = organizationId; + this.httpClient = HttpClient.newHttpClient(); + this.platformUrl = new PlatformUrlBuilder().withEnvironment(environment).build(); + } + + /** + * Create a new push source + * + * @deprecated Please use {@link PlatformClient#createSource(String, SourceType, + * SourceVisibility)} instead + * @param name + * @param sourceVisibility + * @return + * @throws IOException + * @throws InterruptedException + */ + @Deprecated + public HttpResponse createSource(String name, SourceVisibility sourceVisibility) + throws IOException, InterruptedException { + return createSource(name, SourceType.PUSH, sourceVisibility); + } + + /** + * Create a new source + * + * @param name The name of the source to create + * @param sourceType The type of the source to create + * @param sourceVisibility The security option that should be applied to the content of the + * source. See [Content Security](https://docs.coveo.com/en/1779). + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createSource( + String name, final SourceType sourceType, SourceVisibility sourceVisibility) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + + String json = + this.toJSON( + new HashMap<>() { + { + put("sourceType", sourceType.toString()); + put("pushEnabled", sourceType.isPushEnabled()); + put("streamEnabled", sourceType.isStreamEnabled()); + put("name", name); + put("sourceVisibility", sourceVisibility); + } + }); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .POST(HttpRequest.BodyPublishers.ofString(json)) + .uri(URI.create(this.getBaseSourceURL())) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Create or update a security identity. See [Adding a Single Security + * Identity](https://docs.coveo.com/en/167) and [Security Identity + * Models](https://docs.coveo.com/en/139). + * + * @param securityProviderId + * @param securityIdentityModel + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentity( + String securityProviderId, SecurityIdentityModel securityIdentityModel) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + "/permissions"); + + String json = new Gson().toJson(securityIdentityModel); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .PUT(HttpRequest.BodyPublishers.ofString(json)) + .uri(uri) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Create or update a security identity alias. See [Adding a Single + * Alias](https://docs.coveo.com/en/142) and [User Alias Definition + * Examples](https://docs.coveo.com/en/46). + * + * @param securityProviderId + * @param securityIdentityAlias + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentityAlias( + String securityProviderId, SecurityIdentityAliasModel securityIdentityAlias) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + "/mappings"); + + String json = new Gson().toJson(securityIdentityAlias); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .PUT(HttpRequest.BodyPublishers.ofString(json)) + .uri(uri) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Delete a security identity. See [Disabling a Single Security + * Identity](https://docs.coveo.com/en/84). + * + * @param securityProviderId + * @param securityIdentityToDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteSecurityIdentity( + String securityProviderId, SecurityIdentityDelete securityIdentityToDelete) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create(this.getBaseProviderURL(securityProviderId) + "/permissions"); + + String json = new Gson().toJson(securityIdentityToDelete); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .method("DELETE", HttpRequest.BodyPublishers.ofString(json)) + .uri(uri) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Delete old security identities. See [Disabling Old Security + * Identities](https://docs.coveo.com/en/33). + * + * @param securityProviderId + * @param batchDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteOldSecurityIdentities( + String securityProviderId, SecurityIdentityDeleteOptions batchDelete) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBaseProviderURL(securityProviderId) + + String.format( + "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/permissions/olderthan?queueDelay=%s%s", + batchDelete.getQueueDelay(), appendOrderingId(batchDelete.getOrderingId()))); + + HttpRequest request = HttpRequest.newBuilder().headers(headers).DELETE().uri(uri).build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Returns the orderingId for the query string only when a valid orderingId is available. + * + * @param orderingId + * @return + */ + public String appendOrderingId(long orderingId) { + if (orderingId > 0) { + return String.format("&orderingId=%s", orderingId); + } + return ""; + } + + /** + * Manage batches of security identities. See [Manage Batches of Security + * Identities](https://docs.coveo.com/en/55). + * + * @param securityProviderId + * @param batchConfig + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse manageSecurityIdentities( + String securityProviderId, SecurityIdentityBatchConfig batchConfig) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBaseProviderURL(securityProviderId) + + String.format( + "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/permissions/batch?fileId=%s%s", + batchConfig.getFileId(), appendOrderingId(batchConfig.getOrderingId()))); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .PUT(HttpRequest.BodyPublishers.noBody()) + .uri(uri) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Adds or updates an individual item in a push source. See [Adding a Single Item in a Push + * Source](https://docs.coveo.com/en/133). + * + * @param sourceId + * @param documentJSON + * @param documentId + * @param compressionType + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse pushDocument( + String sourceId, String documentJSON, String documentId, CompressionType compressionType) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBasePushURL() + + String.format( + "/sources/%s/documents?documentId=%s&compressionType=%s", + sourceId, documentId, compressionType.toString())); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .PUT(HttpRequest.BodyPublishers.ofString(documentJSON)) + .uri(uri) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Deletes a specific item from a Push source. Optionally, the child items of that item can also + * be deleted. See [Deleting an Item in a Push Source](https://docs.coveo.com/en/171). + * + * @param sourceId + * @param documentId + * @param deleteChildren + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteDocument( + String sourceId, String documentId, Boolean deleteChildren) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBasePushURL() + + String.format( + "/sources/%s/documents?documentId=%s&deleteChildren=%s", + sourceId, documentId, deleteChildren)); + + HttpRequest request = HttpRequest.newBuilder().headers(headers).DELETE().uri(uri).build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + public HttpResponse openStream(String sourceId) throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + // TODO: LENS-875: standardize string manipulation + URI uri = + URI.create(this.getBasePushURL() + String.format("/sources/%s/stream/open", sourceId)); + + // TODO: LENS-876: reduce code duplication + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + public HttpResponse closeStream(String sourceId, String streamId) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBasePushURL() + + String.format("/sources/%s/stream/%s/close", sourceId, streamId)); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + public HttpResponse requireStreamChunk(String sourceId, String streamId) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBasePushURL() + + String.format("/sources/%s/stream/%s/chunk", sourceId, streamId)); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Create a file container. See [Creating a File Container](https://docs.coveo.com/en/43). + * + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createFileContainer() throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create(this.getBasePushURL() + "/files"); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Update the status of a Push source. See [Updating the Status of a Push + * Source](https://docs.coveo.com/en/35). + * + * @param status + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse updateSourceStatus(String sourceId, PushAPIStatus status) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBasePushURL() + + String.format("/sources/%s/status?statusType=%s", sourceId, status.toString())); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .POST(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Upload content update into a file container. See [Upload the Content Update into the File + * Container](https://docs.coveo.com/en/90/index-content/manage-batches-of-items-in-a-push-source#step-2-upload-the-content-update-into-the-file-container). + * + * @param fileContainer + * @param batchUpdateJson + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse uploadContentToFileContainer( + FileContainer fileContainer, String batchUpdateJson) + throws IOException, InterruptedException { + String[] headers = + fileContainer.requiredHeaders.entrySet().stream() + .flatMap(entry -> Stream.of(entry.getKey(), entry.getValue())) + .toArray(String[]::new); + URI uri = URI.create(fileContainer.uploadUri); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .PUT(HttpRequest.BodyPublishers.ofString(batchUpdateJson)) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Push a file container into a push source. See [Push the File Container into a Push + * Source](https://docs.coveo.com/en/90/index-content/manage-batches-of-items-in-a-push-source#step-3-push-the-file-container-into-a-push-source). + * + * @param sourceId + * @param fileContainer + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse pushFileContainerContent(String sourceId, FileContainer fileContainer) + throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = + URI.create( + this.getBasePushURL() + + String.format( + "/sources/%s/documents/batch?fileId=%s", sourceId, fileContainer.fileId)); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .PUT(HttpRequest.BodyPublishers.ofString("")) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + /** + * Push a binary to a File Container. See [Upload the Item Data Into the File + * Container](https://docs.coveo.com/en/69#step-2-upload-the-item-data-into-the-file-container) + * + * @param fileContainer + * @param fileAsBytes + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse pushBinaryToFileContainer( + FileContainer fileContainer, byte[] fileAsBytes) throws IOException, InterruptedException { + String[] headers = + this.getHeaders(this.getAes256Header(), this.getContentTypeApplicationOctetStreamHeader()); + URI uri = URI.create(fileContainer.uploadUri); + + HttpRequest request = + HttpRequest.newBuilder() + .headers(headers) + .uri(uri) + .PUT(HttpRequest.BodyPublishers.ofByteArray(fileAsBytes)) + .build(); + + return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + private String getBaseSourceURL() { + return String.format("%s/sources", this.getBasePlatformURL()); + } + + private String getBasePlatformURL() { + return String.format( + "%s/rest/organizations/%s", this.platformUrl.getPlatformUrl(), this.organizationId); + } + + private String getBasePushURL() { + return String.format( + "%s/push/v1/organizations/%s", this.platformUrl.getApiUrl(), this.organizationId); + } + + private String getBaseProviderURL(String providerId) { + return String.format("%s/providers/%s", this.getBasePushURL(), providerId); + } + + private String[] getHeaders(String[]... headers) { + String[] out = new String[] {}; + for (String[] header : headers) { + out = Stream.concat(Arrays.stream(out), Arrays.stream(header)).toArray(String[]::new); + } + return out; + } + + private String[] getAuthorizationHeader() { + return new String[] {"Authorization", String.format("Bearer %s", this.apiKey)}; + } + + private String[] getContentTypeApplicationJSONHeader() { + return new String[] {"Content-Type", "application/json", "Accept", "application/json"}; + } + + private String[] getAes256Header() { + return new String[] {"x-amz-server-side-encryption", "AES256"}; + } + + private String[] getContentTypeApplicationOctetStreamHeader() { + return new String[] {"Content-Type", "application/octet-stream"}; + } + + private String toJSON(HashMap hashMap) { + return new Gson().toJson(hashMap, new TypeToken>() {}.getType()); + } } diff --git a/src/main/java/com/coveo/pushapiclient/PlatformUrl.java b/src/main/java/com/coveo/pushapiclient/PlatformUrl.java index 5f6830f8..7062dc11 100644 --- a/src/main/java/com/coveo/pushapiclient/PlatformUrl.java +++ b/src/main/java/com/coveo/pushapiclient/PlatformUrl.java @@ -2,41 +2,39 @@ public class PlatformUrl { - public static final Environment DEFAULT_ENVIRONMENT = Environment.PRODUCTION; - public static final Region DEFAULT_REGION = Region.US; - - private final Environment environment; - private final Region region; - - /** - * @param environment The environment platform of your organization - * @param region The physical center of your organization - * - * @see https://docs.coveo.com/en/2976 - */ - public PlatformUrl(Environment environment, Region region) { - this.environment = environment; - this.region = region; - } - - public String getPlatformUrl() { - return String.format("https://platform%s%s.cloud.coveo.com", this.getUrlEnvironment(), this.getUrlRegion()); - } - - public String getApiUrl() { - return String.format("https://api%s%s.cloud.coveo.com", this.getUrlEnvironment(), this.getUrlRegion()); - } - - private String getUrlEnvironment() { - return this.environment == PlatformUrl.DEFAULT_ENVIRONMENT - ? "" - : this.environment.getValue(); - } - - private String getUrlRegion() { - return this.region == PlatformUrl.DEFAULT_REGION - ? "" - : String.format("-%s", this.region.getValue()); - } - + public static final Environment DEFAULT_ENVIRONMENT = Environment.PRODUCTION; + public static final Region DEFAULT_REGION = Region.US; + + private final Environment environment; + private final Region region; + + /** + * @param environment The environment platform of your organization + * @param region The physical center of your organization + * @see https://docs.coveo.com/en/2976 + */ + public PlatformUrl(Environment environment, Region region) { + this.environment = environment; + this.region = region; + } + + public String getPlatformUrl() { + return String.format( + "https://platform%s%s.cloud.coveo.com", this.getUrlEnvironment(), this.getUrlRegion()); + } + + public String getApiUrl() { + return String.format( + "https://api%s%s.cloud.coveo.com", this.getUrlEnvironment(), this.getUrlRegion()); + } + + private String getUrlEnvironment() { + return this.environment == PlatformUrl.DEFAULT_ENVIRONMENT ? "" : this.environment.getValue(); + } + + private String getUrlRegion() { + return this.region == PlatformUrl.DEFAULT_REGION + ? "" + : String.format("-%s", this.region.getValue()); + } } diff --git a/src/main/java/com/coveo/pushapiclient/PlatformUrlBuilder.java b/src/main/java/com/coveo/pushapiclient/PlatformUrlBuilder.java index 3d05ff09..45f26be3 100644 --- a/src/main/java/com/coveo/pushapiclient/PlatformUrlBuilder.java +++ b/src/main/java/com/coveo/pushapiclient/PlatformUrlBuilder.java @@ -2,20 +2,20 @@ public class PlatformUrlBuilder { - private Environment environment = PlatformUrl.DEFAULT_ENVIRONMENT; - private Region region = PlatformUrl.DEFAULT_REGION; + private Environment environment = PlatformUrl.DEFAULT_ENVIRONMENT; + private Region region = PlatformUrl.DEFAULT_REGION; - public PlatformUrlBuilder withEnvironment(Environment environment) { - this.environment = environment; - return this; - } + public PlatformUrlBuilder withEnvironment(Environment environment) { + this.environment = environment; + return this; + } - public PlatformUrlBuilder withRegion(Region region) { - this.region = region; - return this; - } + public PlatformUrlBuilder withRegion(Region region) { + this.region = region; + return this; + } - public PlatformUrl build() { - return new PlatformUrl(this.environment, this.region); - } + public PlatformUrl build() { + return new PlatformUrl(this.environment, this.region); + } } diff --git a/src/main/java/com/coveo/pushapiclient/PushAPIStatus.java b/src/main/java/com/coveo/pushapiclient/PushAPIStatus.java index 7b6a90ee..ad1adacb 100644 --- a/src/main/java/com/coveo/pushapiclient/PushAPIStatus.java +++ b/src/main/java/com/coveo/pushapiclient/PushAPIStatus.java @@ -1,11 +1,12 @@ package com.coveo.pushapiclient; /** - * Enum for possible PushAPI statuses. See [Updating the Status of a Push Source](https://docs.coveo.com/en/35). + * Enum for possible PushAPI statuses. See [Updating the Status of a Push + * Source](https://docs.coveo.com/en/35). */ public enum PushAPIStatus { - IDLE, - REBUILD, - INCREMENTAL, - REFRESH; + IDLE, + REBUILD, + INCREMENTAL, + REFRESH; } diff --git a/src/main/java/com/coveo/pushapiclient/PushEnabledSource.java b/src/main/java/com/coveo/pushapiclient/PushEnabledSource.java index b90b5f1e..e5fa4809 100644 --- a/src/main/java/com/coveo/pushapiclient/PushEnabledSource.java +++ b/src/main/java/com/coveo/pushapiclient/PushEnabledSource.java @@ -1,6 +1,4 @@ package com.coveo.pushapiclient; // Marker Interface -public interface PushEnabledSource extends BaseSource { - -} +public interface PushEnabledSource extends BaseSource {} diff --git a/src/main/java/com/coveo/pushapiclient/PushService.java b/src/main/java/com/coveo/pushapiclient/PushService.java index 185203f0..8691fe83 100644 --- a/src/main/java/com/coveo/pushapiclient/PushService.java +++ b/src/main/java/com/coveo/pushapiclient/PushService.java @@ -1,51 +1,52 @@ package com.coveo.pushapiclient; +import com.google.gson.Gson; import java.io.IOException; import java.net.http.HttpResponse; -import com.google.gson.Gson; - public class PushService { - private final PushEnabledSource source; - private final PlatformClient platformClient; - private PushServiceInternal service; - - public PushService(PushEnabledSource source) { - String apiKey = source.getApiKey(); - String organizationId = source.getOrganizationId(); - PlatformUrl platformUrl = source.getPlatformUrl(); - UploadStrategy uploader = this.getUploadStrategy(); - DocumentUploadQueue queue = new DocumentUploadQueue(uploader); - - this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); - this.service = new PushServiceInternal(queue); - this.source = source; - } - - public void addOrUpdate(DocumentBuilder document) throws IOException, InterruptedException { - // TODO: LENS-843: include partial document updates - this.service.addOrUpdate(document); - } - - public void delete(DeleteDocument document) throws IOException, InterruptedException { - this.service.delete(document); - } - - public void close() throws IOException, InterruptedException { - this.service.close(); - } - - private UploadStrategy getUploadStrategy() { - return (batchUpdate) -> { - String sourceId = this.getSourceId(); - HttpResponse resFileContainer = this.platformClient.createFileContainer(); - FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); - this.platformClient.uploadContentToFileContainer(fileContainer, new Gson().toJson(batchUpdate.marshal())); - return this.platformClient.pushFileContainerContent(sourceId, fileContainer); - }; - } - - private String getSourceId() { - return this.source.getId(); - } + private final PushEnabledSource source; + private final PlatformClient platformClient; + private PushServiceInternal service; + + public PushService(PushEnabledSource source) { + String apiKey = source.getApiKey(); + String organizationId = source.getOrganizationId(); + PlatformUrl platformUrl = source.getPlatformUrl(); + UploadStrategy uploader = this.getUploadStrategy(); + DocumentUploadQueue queue = new DocumentUploadQueue(uploader); + + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + this.service = new PushServiceInternal(queue); + this.source = source; + } + + public void addOrUpdate(DocumentBuilder document) throws IOException, InterruptedException { + // TODO: LENS-843: include partial document updates + this.service.addOrUpdate(document); + } + + public void delete(DeleteDocument document) throws IOException, InterruptedException { + this.service.delete(document); + } + + public void close() throws IOException, InterruptedException { + this.service.close(); + } + + private UploadStrategy getUploadStrategy() { + return (batchUpdate) -> { + String sourceId = this.getSourceId(); + HttpResponse resFileContainer = this.platformClient.createFileContainer(); + FileContainer fileContainer = + new Gson().fromJson(resFileContainer.body(), FileContainer.class); + this.platformClient.uploadContentToFileContainer( + fileContainer, new Gson().toJson(batchUpdate.marshal())); + return this.platformClient.pushFileContainerContent(sourceId, fileContainer); + }; + } + + private String getSourceId() { + return this.source.getId(); + } } diff --git a/src/main/java/com/coveo/pushapiclient/PushServiceInternal.java b/src/main/java/com/coveo/pushapiclient/PushServiceInternal.java index 7f3f0c4c..a082c887 100644 --- a/src/main/java/com/coveo/pushapiclient/PushServiceInternal.java +++ b/src/main/java/com/coveo/pushapiclient/PushServiceInternal.java @@ -3,22 +3,21 @@ import java.io.IOException; public class PushServiceInternal { - private DocumentUploadQueue queue; + private DocumentUploadQueue queue; - public PushServiceInternal(DocumentUploadQueue queue) { - this.queue = queue; - } + public PushServiceInternal(DocumentUploadQueue queue) { + this.queue = queue; + } - public void addOrUpdate(DocumentBuilder document) throws IOException, InterruptedException { - this.queue.add(document); - } + public void addOrUpdate(DocumentBuilder document) throws IOException, InterruptedException { + this.queue.add(document); + } - public void delete(DeleteDocument document) throws IOException, InterruptedException { - this.queue.add(document); - } - - public void close() throws IOException, InterruptedException { - queue.flush(); - } + public void delete(DeleteDocument document) throws IOException, InterruptedException { + this.queue.add(document); + } + public void close() throws IOException, InterruptedException { + queue.flush(); + } } diff --git a/src/main/java/com/coveo/pushapiclient/PushSource.java b/src/main/java/com/coveo/pushapiclient/PushSource.java index b84bf354..b45b2c30 100644 --- a/src/main/java/com/coveo/pushapiclient/PushSource.java +++ b/src/main/java/com/coveo/pushapiclient/PushSource.java @@ -1,7 +1,6 @@ package com.coveo.pushapiclient; import com.google.gson.Gson; - import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -9,322 +8,289 @@ // TODO: LENS-851 - Make public when ready class PushSource implements PushEnabledSource { - private final String apiKey; - private final ApiUrl urlExtractor; - private final PlatformClient platformClient; - - @Override - public String getOrganizationId() { - return this.urlExtractor.getOrganizationId(); - } - - @Override - public PlatformUrl getPlatformUrl() { - return this.urlExtractor.getPlatformUrl(); - } + private final String apiKey; + private final ApiUrl urlExtractor; + private final PlatformClient platformClient; - @Override - public String getId() { - return this.urlExtractor.getSourceId(); - } + @Override + public String getOrganizationId() { + return this.urlExtractor.getOrganizationId(); + } - @Override - public String getApiKey() { - return this.apiKey; - } + @Override + public PlatformUrl getPlatformUrl() { + return this.urlExtractor.getPlatformUrl(); + } - /** - * Creates a push Source in Coveo Org - * - * @param platformClient - * @param name - * @param name The name of the source to create - * @param sourceVisibility The security option that should be applied to the content of the source. See [Content Security](https://docs.coveo.com/en/1779). - * @return - * @throws IOException - * @throws InterruptedException - */ - public static HttpResponse create(PlatformClient platformClient, String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { - return platformClient.createSource(name, SourceType.PUSH, sourceVisibility); - } + @Override + public String getId() { + return this.urlExtractor.getSourceId(); + } - /** - * Create a Push source instance from its - * Push API URL - * - * @param apiKey The API key used for all operations regarding your source. - *

- * Ensure your API key has the required privileges for the - * operation you will be performing - * * - *

- * For more information about which privileges are required, - * see - * Privilege - * Reference. - * - * @param sourceUrl The URL available when you edit your source in the Coveo - * Administration Console. The URL should contain your - * ORGANIZATION_ID and SOURCE_ID, - * which are required parameters for all operations regarding - * your source. - *

- * Some examples of valid source URLs: - * - *

-     * https://api.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/documents
-     * https://api-eu.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/documents
-     *                  
- * - * @throws MalformedURLException - */ - public PushSource(String apiKey, URL sourceUrl) throws MalformedURLException { - this.apiKey = apiKey; - this.urlExtractor = new ApiUrl(sourceUrl); - String organizationId = urlExtractor.getOrganizationId(); - PlatformUrl platformUrl = urlExtractor.getPlatformUrl(); - this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); - } + @Override + public String getApiKey() { + return this.apiKey; + } - /** - * Create a Push source instance - * - * @param apiKey The API key used for all operations regarding your - * source. - *

- * Ensure your API key has the required privileges for the - * operation you will be performing - * * - *

- * For more information about which privileges are - * required, - * see - * Privilege - * Reference. - * - * @param organizationId The unique identifier of your organization. - *

- * The Organization Id can be retrieved in the URL of your - * Coveo organization. - * - * @param sourceId The unique identifier of the target Push source. - *

- * The Source Id can be retrieved when you edit your - * source in the Coveo - * Administration Console - * - */ - public static PushSource fromPlatformUrl(String apiKey, String organizationId, String sourceId) { - PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); - return new PushSource(apiKey, organizationId, sourceId, platformUrl); - } + /** + * Creates a push Source + * in Coveo Org + * + * @param platformClient + * @param name + * @param name The name of the source to create + * @param sourceVisibility The security option that should be applied to the content of the + * source. See [Content Security](https://docs.coveo.com/en/1779). + * @return + * @throws IOException + * @throws InterruptedException + */ + public static HttpResponse create( + PlatformClient platformClient, String name, SourceVisibility sourceVisibility) + throws IOException, InterruptedException { + return platformClient.createSource(name, SourceType.PUSH, sourceVisibility); + } - /** - * Create a Push source instance - * - * @param apiKey The API key used for all operations regarding your - * source. - *

- * Ensure your API key has the required privileges for the - * operation you will be performing - * * - *

- * For more information about which privileges are - * required, - * see - * Privilege - * Reference. - * - * @param organizationId The unique identifier of your organization. - *

- * The Organization Id can be retrieved in the URL of your - * Coveo organization. - * - * @param sourceId The unique identifier of the target Push source. - *

- * The Source Id can be retrieved when you edit your - * source in the Coveo - * Administration Console - * - * @param platformUrl The object containing additional information on the - * URL endpoint. - * You can use the {@link PlatformUrl} when your - * organization is located in a non-default Coveo - * environement and/or region. When not specified, the - * default platform URL values will be used: - * {@link PlatformUrl#DEFAULT_ENVIRONMENT} and - * {@link PlatformUrl#DEFAULT_REGION} - * - */ - public static PushSource fromPlatformUrl(String apiKey, String organizationId, String sourceId, - PlatformUrl platformUrl) { - return new PushSource(apiKey, organizationId, sourceId, platformUrl); - } + /** + * Create a Push source instance from its Push API URL + * + * @param apiKey The API key used for all operations regarding your source. + *

Ensure your API key has the required privileges for the operation you will be performing + * * + *

For more information about which privileges are required, see Privilege Reference. + * @param sourceUrl The URL available when you edit your source in the Coveo Administration + * Console. The URL should contain your ORGANIZATION_ID and SOURCE_ID + * , which are required parameters for all operations regarding your source. + *

Some examples of valid source URLs: + *

+   * https://api.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/documents
+   * https://api-eu.cloud.coveo.com/push/v1/organizations/my-org-if/sources/my-source-id/documents
+   *                  
+ * + * @throws MalformedURLException + */ + public PushSource(String apiKey, URL sourceUrl) throws MalformedURLException { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(sourceUrl); + String organizationId = urlExtractor.getOrganizationId(); + PlatformUrl platformUrl = urlExtractor.getPlatformUrl(); + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + } - private PushSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { - this.apiKey = apiKey; - this.urlExtractor = new ApiUrl(organizationId, sourceId, platformUrl); - this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); - } + /** + * Create a Push source instance + * + * @param apiKey The API key used for all operations regarding your source. + *

Ensure your API key has the required privileges for the operation you will be performing + * * + *

For more information about which privileges are required, see Privilege Reference. + * @param organizationId The unique identifier of your organization. + *

The Organization Id can be retrieved in the URL of your Coveo organization. + * @param sourceId The unique identifier of the target Push source. + *

The Source Id can be retrieved when you edit your source in the Coveo Administration + * Console + */ + public static PushSource fromPlatformUrl(String apiKey, String organizationId, String sourceId) { + PlatformUrl platformUrl = + new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); + return new PushSource(apiKey, organizationId, sourceId, platformUrl); + } - /** - * Create or update a security identity. See [Adding a Single Security - * Identity](https://docs.coveo.com/en/167) and [Security Identity - * Models](https://docs.coveo.com/en/139). - * - * @param securityProviderId - * @param securityIdentityModel - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createOrUpdateSecurityIdentity(String securityProviderId, - SecurityIdentityModel securityIdentityModel) throws IOException, InterruptedException { - return this.platformClient.createOrUpdateSecurityIdentity(securityProviderId, securityIdentityModel); - } + /** + * Create a Push source instance + * + * @param apiKey The API key used for all operations regarding your source. + *

Ensure your API key has the required privileges for the operation you will be performing + * * + *

For more information about which privileges are required, see Privilege Reference. + * @param organizationId The unique identifier of your organization. + *

The Organization Id can be retrieved in the URL of your Coveo organization. + * @param sourceId The unique identifier of the target Push source. + *

The Source Id can be retrieved when you edit your source in the Coveo Administration + * Console + * @param platformUrl The object containing additional information on the URL endpoint. You can + * use the {@link PlatformUrl} when your organization is located in a non-default Coveo + * environement and/or region. When not specified, the default platform URL values will be + * used: {@link PlatformUrl#DEFAULT_ENVIRONMENT} and {@link PlatformUrl#DEFAULT_REGION} + */ + public static PushSource fromPlatformUrl( + String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + return new PushSource(apiKey, organizationId, sourceId, platformUrl); + } - /** - * Create or update a security identity alias. See [Adding a Single - * Alias](https://docs.coveo.com/en/142) and [User Alias Definition - * Examples](https://docs.coveo.com/en/46). - * - * @param securityProviderId - * @param securityIdentityAliasModel - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createOrUpdateSecurityIdentityAlias(String securityProviderId, - SecurityIdentityAliasModel securityIdentityAliasModel) throws IOException, InterruptedException { - return this.platformClient.createOrUpdateSecurityIdentityAlias(securityProviderId, securityIdentityAliasModel); - } + private PushSource( + String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(organizationId, sourceId, platformUrl); + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + } - /** - * Delete a security identity. See [Disabling a Single Security - * Identity](https://docs.coveo.com/en/84). - * - * @param securityProviderId - * @param securityIdentityDelete - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteSecurityIdentity(String securityProviderId, - SecurityIdentityDelete securityIdentityDelete) throws IOException, InterruptedException { - return this.platformClient.deleteSecurityIdentity(securityProviderId, securityIdentityDelete); - } + /** + * Create or update a security identity. See [Adding a Single Security + * Identity](https://docs.coveo.com/en/167) and [Security Identity + * Models](https://docs.coveo.com/en/139). + * + * @param securityProviderId + * @param securityIdentityModel + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentity( + String securityProviderId, SecurityIdentityModel securityIdentityModel) + throws IOException, InterruptedException { + return this.platformClient.createOrUpdateSecurityIdentity( + securityProviderId, securityIdentityModel); + } - /** - * Update the status of a Push source. See [Updating the Status of a Push - * Source](https://docs.coveo.com/en/35). - * - * @param status - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse updateSourceStatus(PushAPIStatus status) - throws IOException, InterruptedException { - return this.platformClient.updateSourceStatus(this.getId(), status); - } + /** + * Create or update a security identity alias. See [Adding a Single + * Alias](https://docs.coveo.com/en/142) and [User Alias Definition + * Examples](https://docs.coveo.com/en/46). + * + * @param securityProviderId + * @param securityIdentityAliasModel + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentityAlias( + String securityProviderId, SecurityIdentityAliasModel securityIdentityAliasModel) + throws IOException, InterruptedException { + return this.platformClient.createOrUpdateSecurityIdentityAlias( + securityProviderId, securityIdentityAliasModel); + } - /** - * Delete old security identities. See [Disabling Old Security - * Identities](https://docs.coveo.com/en/33). - * - * @param securityProviderId - * @param batchDelete - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteOldSecurityIdentities(String securityProviderId, - SecurityIdentityDeleteOptions batchDelete) throws IOException, InterruptedException { - return this.platformClient.deleteOldSecurityIdentities(securityProviderId, batchDelete); - } + /** + * Delete a security identity. See [Disabling a Single Security + * Identity](https://docs.coveo.com/en/84). + * + * @param securityProviderId + * @param securityIdentityDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteSecurityIdentity( + String securityProviderId, SecurityIdentityDelete securityIdentityDelete) + throws IOException, InterruptedException { + return this.platformClient.deleteSecurityIdentity(securityProviderId, securityIdentityDelete); + } - /** - * Manage batches of security identities. See [Manage Batches of Security - * Identities](https://docs.coveo.com/en/55). - * - * @param securityProviderId - * @param batchConfig - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse manageSecurityIdentities(String securityProviderId, - SecurityIdentityBatchConfig batchConfig) throws IOException, InterruptedException { - return this.platformClient.manageSecurityIdentities(securityProviderId, batchConfig); - } + /** + * Update the status of a Push source. See [Updating the Status of a Push + * Source](https://docs.coveo.com/en/35). + * + * @param status + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse updateSourceStatus(PushAPIStatus status) + throws IOException, InterruptedException { + return this.platformClient.updateSourceStatus(this.getId(), status); + } - /** - * Manages pushing batches of Security Identities to a File Container, then into - * Coveo. See [Manage Batches of Security - * Identities](https://docs.coveo.com/en/55) - * - * @param securityProviderId - * @param batchIdentity - * @return - * @throws IOException - * @throws InterruptedException - */ - public SecurityIdentityBatchResponse batchUpdateSecurityIdentities(String securityProviderId, - BatchIdentity batchIdentity) throws IOException, InterruptedException { - SecurityIdentityBatchResponse securityIdentityBatchResponse = new SecurityIdentityBatchResponse(); - HttpResponse resFileContainer = this.platformClient.createFileContainer(); - FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); - String batchIdJson = new Gson().toJson(batchIdentity.marshal()); - securityIdentityBatchResponse.s3Response = this.platformClient.uploadContentToFileContainer(fileContainer, - batchIdJson); - if (securityIdentityBatchResponse.s3Response.statusCode() >= 200 - && securityIdentityBatchResponse.s3Response.statusCode() <= 299) { // maybe just 200 or 202 - SecurityIdentityBatchConfig batchConfig = new SecurityIdentityBatchConfig(fileContainer.fileId, 0l); - securityIdentityBatchResponse.batchResponse = this.manageSecurityIdentities(securityProviderId, - batchConfig); - } - return securityIdentityBatchResponse; - } + /** + * Delete old security identities. See [Disabling Old Security + * Identities](https://docs.coveo.com/en/33). + * + * @param securityProviderId + * @param batchDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteOldSecurityIdentities( + String securityProviderId, SecurityIdentityDeleteOptions batchDelete) + throws IOException, InterruptedException { + return this.platformClient.deleteOldSecurityIdentities(securityProviderId, batchDelete); + } - /** - * Adds or updates an individual item in a push source. See [Adding a Single - * Item in a Push Source](https://docs.coveo.com/en/133). - * - * @param docBuilder - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse addOrUpdateDocument(DocumentBuilder docBuilder) - throws IOException, InterruptedException { - CompressionType compressionType = docBuilder.getDocument().compressedBinaryData != null - ? docBuilder.getDocument().compressedBinaryData.getCompressionType() - : CompressionType.UNCOMPRESSED; - return this.platformClient.pushDocument(this.getId(), docBuilder.marshal(), docBuilder.getDocument().uri, - compressionType); - } + /** + * Manage batches of security identities. See [Manage Batches of Security + * Identities](https://docs.coveo.com/en/55). + * + * @param securityProviderId + * @param batchConfig + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse manageSecurityIdentities( + String securityProviderId, SecurityIdentityBatchConfig batchConfig) + throws IOException, InterruptedException { + return this.platformClient.manageSecurityIdentities(securityProviderId, batchConfig); + } - /** - * Deletes a specific item from a Push source. Optionally, the child items of - * that item can also be deleted. See [Deleting an Item in a Push - * Source](https://docs.coveo.com/en/171). - * - * @param documentId - * @param deleteChildren - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteDocument(String documentId, Boolean deleteChildren) - throws IOException, InterruptedException { - return this.platformClient.deleteDocument(this.getId(), documentId, deleteChildren); + /** + * Manages pushing batches of Security Identities to a File Container, then into Coveo. See + * [Manage Batches of Security Identities](https://docs.coveo.com/en/55) + * + * @param securityProviderId + * @param batchIdentity + * @return + * @throws IOException + * @throws InterruptedException + */ + public SecurityIdentityBatchResponse batchUpdateSecurityIdentities( + String securityProviderId, BatchIdentity batchIdentity) + throws IOException, InterruptedException { + SecurityIdentityBatchResponse securityIdentityBatchResponse = + new SecurityIdentityBatchResponse(); + HttpResponse resFileContainer = this.platformClient.createFileContainer(); + FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); + String batchIdJson = new Gson().toJson(batchIdentity.marshal()); + securityIdentityBatchResponse.s3Response = + this.platformClient.uploadContentToFileContainer(fileContainer, batchIdJson); + if (securityIdentityBatchResponse.s3Response.statusCode() >= 200 + && securityIdentityBatchResponse.s3Response.statusCode() <= 299) { // maybe just 200 or 202 + SecurityIdentityBatchConfig batchConfig = + new SecurityIdentityBatchConfig(fileContainer.fileId, 0l); + securityIdentityBatchResponse.batchResponse = + this.manageSecurityIdentities(securityProviderId, batchConfig); } + return securityIdentityBatchResponse; + } + /** + * Adds or updates an individual item in a push source. See [Adding a Single Item in a Push + * Source](https://docs.coveo.com/en/133). + * + * @param docBuilder + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse addOrUpdateDocument(DocumentBuilder docBuilder) + throws IOException, InterruptedException { + CompressionType compressionType = + docBuilder.getDocument().compressedBinaryData != null + ? docBuilder.getDocument().compressedBinaryData.getCompressionType() + : CompressionType.UNCOMPRESSED; + return this.platformClient.pushDocument( + this.getId(), docBuilder.marshal(), docBuilder.getDocument().uri, compressionType); + } + /** + * Deletes a specific item from a Push source. Optionally, the child items of that item can also + * be deleted. See [Deleting an Item in a Push Source](https://docs.coveo.com/en/171). + * + * @param documentId + * @param deleteChildren + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteDocument(String documentId, Boolean deleteChildren) + throws IOException, InterruptedException { + return this.platformClient.deleteDocument(this.getId(), documentId, deleteChildren); + } } diff --git a/src/main/java/com/coveo/pushapiclient/Region.java b/src/main/java/com/coveo/pushapiclient/Region.java index 6e6a6df9..2c42691e 100644 --- a/src/main/java/com/coveo/pushapiclient/Region.java +++ b/src/main/java/com/coveo/pushapiclient/Region.java @@ -1,20 +1,18 @@ package com.coveo.pushapiclient; -/** - * Available Platform regions to connect to - */ +/** Available Platform regions to connect to */ public enum Region { - US("us"), - EU("eu"), - AU("au"); + US("us"), + EU("eu"), + AU("au"); - private String value; + private String value; - Region(String value) { - this.value = value; - } + Region(String value) { + this.value = value; + } - public String getValue() { - return this.value; - } -} \ No newline at end of file + public String getValue() { + return this.value; + } +} diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentity.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentity.java index 998cd4e3..a53dfd5f 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentity.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentity.java @@ -1,33 +1,33 @@ package com.coveo.pushapiclient; public class SecurityIdentity { - /** - * The name of the security identity. - *

- * Examples: - * - `asmith@example.com` - * - `SampleTeam2` - */ - public String identity; - /** - * The type of the identity. - * Valid values: - * - `UNKNOWN` - * - `USER` : Defines a single user. - * - `GROUP` : Defines an existing group of identities within the indexed system. Individual members of this group can be of any valid identity Type (USER, GROUP, or VIRTUAL_GROUP). - * - `VIRTUAL_GROUP` : Defines a group that doesn't exist within the indexed system. Mechanically, a `VIRTUAL_GROUP` is identical to a `GROUP`. - */ - public SecurityIdentityType identityType; - /** - * The security identity provider through which the security identity is updated. - *

- * Defaults to the first security identity provider associated with the target Push source. - */ - public String securityProvider; + /** + * The name of the security identity. + * + *

Examples: - `asmith@example.com` - `SampleTeam2` + */ + public String identity; - public SecurityIdentity(String identity, SecurityIdentityType securityIdentityType, String securityProvider) { - this.identity = identity; - this.identityType = securityIdentityType; - this.securityProvider = securityProvider; - } -} \ No newline at end of file + /** + * The type of the identity. Valid values: - `UNKNOWN` - `USER` : Defines a single user. - `GROUP` + * : Defines an existing group of identities within the indexed system. Individual members of this + * group can be of any valid identity Type (USER, GROUP, or VIRTUAL_GROUP). - `VIRTUAL_GROUP` : + * Defines a group that doesn't exist within the indexed system. Mechanically, a `VIRTUAL_GROUP` + * is identical to a `GROUP`. + */ + public SecurityIdentityType identityType; + + /** + * The security identity provider through which the security identity is updated. + * + *

Defaults to the first security identity provider associated with the target Push source. + */ + public String securityProvider; + + public SecurityIdentity( + String identity, SecurityIdentityType securityIdentityType, String securityProvider) { + this.identity = identity; + this.identityType = securityIdentityType; + this.securityProvider = securityProvider; + } +} diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityAliasModel.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityAliasModel.java index 631e8940..4d66a4a5 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityAliasModel.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityAliasModel.java @@ -1,13 +1,12 @@ package com.coveo.pushapiclient; -/** - * See [User Alias Definition Examples](https://docs.coveo.com/en/46). - */ +/** See [User Alias Definition Examples](https://docs.coveo.com/en/46). */ public class SecurityIdentityAliasModel extends SecurityIdentityModelBase { - public final AliasMapping[] mappings; + public final AliasMapping[] mappings; - public SecurityIdentityAliasModel(AliasMapping[] mappings, IdentityModel identity, IdentityModel[] wellKnowns) { - super(identity, wellKnowns); - this.mappings = mappings; - } + public SecurityIdentityAliasModel( + AliasMapping[] mappings, IdentityModel identity, IdentityModel[] wellKnowns) { + super(identity, wellKnowns); + this.mappings = mappings; + } } diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchConfig.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchConfig.java index 1fc99d63..74cb66b4 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchConfig.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchConfig.java @@ -2,45 +2,46 @@ import java.util.Objects; -/** - * See [Manage Batches of Security Identities](https://docs.coveo.com/en/55). - */ +/** See [Manage Batches of Security Identities](https://docs.coveo.com/en/55). */ public class SecurityIdentityBatchConfig { - private final String fileId; - private final Long orderingId; - - public SecurityIdentityBatchConfig(String fileId, Long orderingId) { - this.fileId = fileId; - this.orderingId = orderingId; - } - - public String getFileId() { - return fileId; - } - - public Long getOrderingId() { - return orderingId; - } - - @Override - public String toString() { - return "SecurityIdentityBatchConfig[" + - "fileId='" + fileId + '\'' + - ", orderingId=" + orderingId + - ']'; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - SecurityIdentityBatchConfig that = (SecurityIdentityBatchConfig) obj; - return Objects.equals(fileId, that.fileId) && Objects.equals(orderingId, that.orderingId); - } - - @Override - public int hashCode() { - return Objects.hash(fileId, orderingId); - } + private final String fileId; + private final Long orderingId; + + public SecurityIdentityBatchConfig(String fileId, Long orderingId) { + this.fileId = fileId; + this.orderingId = orderingId; + } + + public String getFileId() { + return fileId; + } + + public Long getOrderingId() { + return orderingId; + } + + @Override + public String toString() { + return "SecurityIdentityBatchConfig[" + + "fileId='" + + fileId + + '\'' + + ", orderingId=" + + orderingId + + ']'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + SecurityIdentityBatchConfig that = (SecurityIdentityBatchConfig) obj; + return Objects.equals(fileId, that.fileId) && Objects.equals(orderingId, that.orderingId); + } + + @Override + public int hashCode() { + return Objects.hash(fileId, orderingId); + } } diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchResponse.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchResponse.java index 58694f34..f8f51848 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchResponse.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityBatchResponse.java @@ -3,26 +3,27 @@ import java.net.http.HttpResponse; /** - * Used for the responses when pushing batches of Security Identities. See [Manage Batches of Security Identities](https://docs.coveo.com/en/55) + * Used for the responses when pushing batches of Security Identities. See [Manage Batches of + * Security Identities](https://docs.coveo.com/en/55) */ public class SecurityIdentityBatchResponse { - protected HttpResponse s3Response; - protected HttpResponse batchResponse; + protected HttpResponse s3Response; + protected HttpResponse batchResponse; - public HttpResponse getS3Response() { - return s3Response; - } + public HttpResponse getS3Response() { + return s3Response; + } - public void setS3Response(HttpResponse s3Response) { - this.s3Response = s3Response; - } + public void setS3Response(HttpResponse s3Response) { + this.s3Response = s3Response; + } - public HttpResponse getBatchResponse() { - return batchResponse; - } + public HttpResponse getBatchResponse() { + return batchResponse; + } - public void setBatchResponse(HttpResponse batchResponse) { - this.batchResponse = batchResponse; - } + public void setBatchResponse(HttpResponse batchResponse) { + this.batchResponse = batchResponse; + } } diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityBuilder.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityBuilder.java index 6b69ddcc..e8884ecf 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityBuilder.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityBuilder.java @@ -1,14 +1,11 @@ package com.coveo.pushapiclient; -/** - * Build a security identity. See {@link SecurityIdentity}. - */ +/** Build a security identity. See {@link SecurityIdentity}. */ public interface SecurityIdentityBuilder { - /** - * Build and return a list of {@link SecurityIdentity} - * - * @return - */ - SecurityIdentity[] build(); + /** + * Build and return a list of {@link SecurityIdentity} + * + * @return + */ + SecurityIdentity[] build(); } - diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityDelete.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityDelete.java index ce5884bb..7df5c128 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityDelete.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityDelete.java @@ -2,38 +2,34 @@ import java.util.Objects; -/** - * See [Disabling a Single Security Identity](https://docs.coveo.com/en/84) - */ +/** See [Disabling a Single Security Identity](https://docs.coveo.com/en/84) */ public class SecurityIdentityDelete { - private final IdentityModel identity; - - public SecurityIdentityDelete(IdentityModel identity) { - this.identity = identity; - } - - public IdentityModel getIdentity() { - return identity; - } - - @Override - public String toString() { - return "SecurityIdentityDelete[" + - "identity=" + identity + - ']'; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - SecurityIdentityDelete that = (SecurityIdentityDelete) obj; - return Objects.equals(identity, that.identity); - } - - @Override - public int hashCode() { - return Objects.hash(identity); - } + private final IdentityModel identity; + + public SecurityIdentityDelete(IdentityModel identity) { + this.identity = identity; + } + + public IdentityModel getIdentity() { + return identity; + } + + @Override + public String toString() { + return "SecurityIdentityDelete[" + "identity=" + identity + ']'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + SecurityIdentityDelete that = (SecurityIdentityDelete) obj; + return Objects.equals(identity, that.identity); + } + + @Override + public int hashCode() { + return Objects.hash(identity); + } } diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptions.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptions.java index 28861303..21147653 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptions.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptions.java @@ -2,45 +2,47 @@ import java.util.Objects; -/** - * See [Disabling Old Security Identities](https://docs.coveo.com/en/33) - */ +/** See [Disabling Old Security Identities](https://docs.coveo.com/en/33) */ public class SecurityIdentityDeleteOptions { - private final Integer queueDelay; - private final Long orderingId; - - public SecurityIdentityDeleteOptions(Integer queueDelay, Long orderingId) { - this.queueDelay = queueDelay; - this.orderingId = orderingId; - } - - public Integer getQueueDelay() { - return queueDelay; - } - - public Long getOrderingId() { - return orderingId; - } - - @Override - public String toString() { - return "SecurityIdentityDeleteOptions" + "[" + - "queueDelay=" + queueDelay + - ", orderingId=" + orderingId + - ']'; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - SecurityIdentityDeleteOptions that = (SecurityIdentityDeleteOptions) obj; - return Objects.equals(queueDelay, that.queueDelay) && Objects.equals(orderingId, that.orderingId); - } - - @Override - public int hashCode() { - return Objects.hash(queueDelay, orderingId); - } + private final Integer queueDelay; + private final Long orderingId; + + public SecurityIdentityDeleteOptions(Integer queueDelay, Long orderingId) { + this.queueDelay = queueDelay; + this.orderingId = orderingId; + } + + public Integer getQueueDelay() { + return queueDelay; + } + + public Long getOrderingId() { + return orderingId; + } + + @Override + public String toString() { + return "SecurityIdentityDeleteOptions" + + "[" + + "queueDelay=" + + queueDelay + + ", orderingId=" + + orderingId + + ']'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + SecurityIdentityDeleteOptions that = (SecurityIdentityDeleteOptions) obj; + return Objects.equals(queueDelay, that.queueDelay) + && Objects.equals(orderingId, that.orderingId); + } + + @Override + public int hashCode() { + return Objects.hash(queueDelay, orderingId); + } } diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityModel.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityModel.java index 1dbb1e81..8cdaf7eb 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityModel.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityModel.java @@ -1,13 +1,12 @@ package com.coveo.pushapiclient; -/** - * See [Security Identity Models](https://docs.coveo.com/en/139) - */ +/** See [Security Identity Models](https://docs.coveo.com/en/139) */ public class SecurityIdentityModel extends SecurityIdentityModelBase { - public final IdentityModel[] members; + public final IdentityModel[] members; - public SecurityIdentityModel(IdentityModel[] members, IdentityModel identity, IdentityModel[] wellKnowns) { - super(identity, wellKnowns); - this.members = members; - } + public SecurityIdentityModel( + IdentityModel[] members, IdentityModel identity, IdentityModel[] wellKnowns) { + super(identity, wellKnowns); + this.members = members; + } } diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityModelBase.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityModelBase.java index ad1b63b8..14181bdd 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityModelBase.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityModelBase.java @@ -1,11 +1,11 @@ package com.coveo.pushapiclient; public class SecurityIdentityModelBase { - public final IdentityModel identity; - public final IdentityModel[] wellKnowns; + public final IdentityModel identity; + public final IdentityModel[] wellKnowns; - public SecurityIdentityModelBase(IdentityModel identity, IdentityModel[] wellKnowns) { - this.identity = identity; - this.wellKnowns = wellKnowns; - } + public SecurityIdentityModelBase(IdentityModel identity, IdentityModel[] wellKnowns) { + this.identity = identity; + this.wellKnowns = wellKnowns; + } } diff --git a/src/main/java/com/coveo/pushapiclient/SecurityIdentityType.java b/src/main/java/com/coveo/pushapiclient/SecurityIdentityType.java index 56e3d23e..70897c44 100644 --- a/src/main/java/com/coveo/pushapiclient/SecurityIdentityType.java +++ b/src/main/java/com/coveo/pushapiclient/SecurityIdentityType.java @@ -1,24 +1,24 @@ package com.coveo.pushapiclient; public enum SecurityIdentityType { - UNKNOWN { - public String toString() { - return "UNKNOWN"; - } - }, - USER { - public String toString() { - return "USER"; - } - }, - GROUP { - public String toString() { - return "GROUP"; - } - }, - VIRTUAL_GROUP { - public String toString() { - return "VIRTUAL_GROUP"; - } + UNKNOWN { + public String toString() { + return "UNKNOWN"; } -} \ No newline at end of file + }, + USER { + public String toString() { + return "USER"; + } + }, + GROUP { + public String toString() { + return "GROUP"; + } + }, + VIRTUAL_GROUP { + public String toString() { + return "VIRTUAL_GROUP"; + } + } +} diff --git a/src/main/java/com/coveo/pushapiclient/Source.java b/src/main/java/com/coveo/pushapiclient/Source.java index 475d3e5c..36772c12 100644 --- a/src/main/java/com/coveo/pushapiclient/Source.java +++ b/src/main/java/com/coveo/pushapiclient/Source.java @@ -1,227 +1,269 @@ package com.coveo.pushapiclient; import com.google.gson.Gson; - import java.io.IOException; import java.net.http.HttpResponse; // TODO: LENS-844 - Deprecate class public class Source { - PlatformClient platformClient; - - /** - * @param apiKey An apiKey capable of pushing documents and managing - * sources in a Coveo organization. See [Manage API - * Keys](https://docs.coveo.com/en/1718). - * @param organizationId The Coveo Organization identifier. - */ - public Source(String apiKey, String organizationId) { - this.platformClient = new PlatformClient(apiKey, organizationId); - } + PlatformClient platformClient; - /** - * @param apiKey An apiKey capable of pushing documents and managing - * sources in a Coveo organization. See [Manage API - * Keys](https://docs.coveo.com/en/1718). - * @param organizationId The Coveo Organization identifier. - * @param platformUrl - */ - public Source(String apiKey, String organizationId, PlatformUrl platformUrl) { - this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); - } + /** + * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo + * organization. See [Manage API Keys](https://docs.coveo.com/en/1718). + * @param organizationId The Coveo Organization identifier. + */ + public Source(String apiKey, String organizationId) { + this.platformClient = new PlatformClient(apiKey, organizationId); + } - /** - * @deprecated Please now use PlatformUrl to define your Platform environment - * @see PlatformUrl Construct a PlatformUrl - * - * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo organization. See [Manage API Keys](https://docs.coveo.com/en/1718). - * @param organizationId The Coveo Organization identifier. - * @param environment The Environment to be used. - */ - @Deprecated - public Source(String apiKey, String organizationId, Environment environment) { - this.platformClient = new PlatformClient(apiKey, organizationId, environment); - } + /** + * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo + * organization. See [Manage API Keys](https://docs.coveo.com/en/1718). + * @param organizationId The Coveo Organization identifier. + * @param platformUrl + */ + public Source(String apiKey, String organizationId, PlatformUrl platformUrl) { + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + } - /** - * Create a new push source. - * - * @param name The name of the source to create - * @param sourceVisibility The security option that should be applied to the content of the source. See [Content Security](https://docs.coveo.com/en/1779). - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse create(String name, SourceVisibility sourceVisibility) throws IOException, InterruptedException { - return this.platformClient.createSource(name, SourceType.PUSH, sourceVisibility); - } + /** + * @deprecated Please now use PlatformUrl to define your Platform environment + * @see PlatformUrl Construct a PlatformUrl + * @param apiKey An apiKey capable of pushing documents and managing sources in a Coveo + * organization. See [Manage API Keys](https://docs.coveo.com/en/1718). + * @param organizationId The Coveo Organization identifier. + * @param environment The Environment to be used. + */ + @Deprecated + public Source(String apiKey, String organizationId, Environment environment) { + this.platformClient = new PlatformClient(apiKey, organizationId, environment); + } - /** - * Create or update a security identity. See [Adding a Single Security Identity](https://docs.coveo.com/en/167) and [Security Identity Models](https://docs.coveo.com/en/139). - * - * @param securityProviderId - * @param securityIdentityModel - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createOrUpdateSecurityIdentity(String securityProviderId, SecurityIdentityModel securityIdentityModel) throws IOException, InterruptedException { - return this.platformClient.createOrUpdateSecurityIdentity(securityProviderId, securityIdentityModel); - } + /** + * Create a new push source. + * + * @param name The name of the source to create + * @param sourceVisibility The security option that should be applied to the content of the + * source. See [Content Security](https://docs.coveo.com/en/1779). + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse create(String name, SourceVisibility sourceVisibility) + throws IOException, InterruptedException { + return this.platformClient.createSource(name, SourceType.PUSH, sourceVisibility); + } - /** - * Create or update a security identity alias. See [Adding a Single Alias](https://docs.coveo.com/en/142) and [User Alias Definition Examples](https://docs.coveo.com/en/46). - * - * @param securityProviderId - * @param securityIdentityAliasModel - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse createOrUpdateSecurityIdentityAlias(String securityProviderId, SecurityIdentityAliasModel securityIdentityAliasModel) throws IOException, InterruptedException { - return this.platformClient.createOrUpdateSecurityIdentityAlias(securityProviderId, securityIdentityAliasModel); - } + /** + * Create or update a security identity. See [Adding a Single Security + * Identity](https://docs.coveo.com/en/167) and [Security Identity + * Models](https://docs.coveo.com/en/139). + * + * @param securityProviderId + * @param securityIdentityModel + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentity( + String securityProviderId, SecurityIdentityModel securityIdentityModel) + throws IOException, InterruptedException { + return this.platformClient.createOrUpdateSecurityIdentity( + securityProviderId, securityIdentityModel); + } - /** - * Delete a security identity. See [Disabling a Single Security Identity](https://docs.coveo.com/en/84). - * - * @param securityProviderId - * @param securityIdentityDelete - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteSecurityIdentity(String securityProviderId, SecurityIdentityDelete securityIdentityDelete) throws IOException, InterruptedException { - return this.platformClient.deleteSecurityIdentity(securityProviderId, securityIdentityDelete); - } + /** + * Create or update a security identity alias. See [Adding a Single + * Alias](https://docs.coveo.com/en/142) and [User Alias Definition + * Examples](https://docs.coveo.com/en/46). + * + * @param securityProviderId + * @param securityIdentityAliasModel + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse createOrUpdateSecurityIdentityAlias( + String securityProviderId, SecurityIdentityAliasModel securityIdentityAliasModel) + throws IOException, InterruptedException { + return this.platformClient.createOrUpdateSecurityIdentityAlias( + securityProviderId, securityIdentityAliasModel); + } - /** - * Update the status of a Push source. See [Updating the Status of a Push Source](https://docs.coveo.com/en/35). - * - * @param sourceId - * @param status - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse updateSourceStatus(String sourceId, PushAPIStatus status) throws IOException, InterruptedException { - return this.platformClient.updateSourceStatus(sourceId, status); - } + /** + * Delete a security identity. See [Disabling a Single Security + * Identity](https://docs.coveo.com/en/84). + * + * @param securityProviderId + * @param securityIdentityDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteSecurityIdentity( + String securityProviderId, SecurityIdentityDelete securityIdentityDelete) + throws IOException, InterruptedException { + return this.platformClient.deleteSecurityIdentity(securityProviderId, securityIdentityDelete); + } - /** - * Delete old security identities. See [Disabling Old Security Identities](https://docs.coveo.com/en/33). - * - * @param securityProviderId - * @param batchDelete - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteOldSecurityIdentities(String securityProviderId, SecurityIdentityDeleteOptions batchDelete) throws IOException, InterruptedException { - return this.platformClient.deleteOldSecurityIdentities(securityProviderId, batchDelete); - } + /** + * Update the status of a Push source. See [Updating the Status of a Push + * Source](https://docs.coveo.com/en/35). + * + * @param sourceId + * @param status + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse updateSourceStatus(String sourceId, PushAPIStatus status) + throws IOException, InterruptedException { + return this.platformClient.updateSourceStatus(sourceId, status); + } - /** - * Manage batches of security identities. See [Manage Batches of Security Identities](https://docs.coveo.com/en/55). - * - * @param securityProviderId - * @param batchConfig - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse manageSecurityIdentities(String securityProviderId, SecurityIdentityBatchConfig batchConfig) throws IOException, InterruptedException { - return this.platformClient.manageSecurityIdentities(securityProviderId, batchConfig); - } + /** + * Delete old security identities. See [Disabling Old Security + * Identities](https://docs.coveo.com/en/33). + * + * @param securityProviderId + * @param batchDelete + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteOldSecurityIdentities( + String securityProviderId, SecurityIdentityDeleteOptions batchDelete) + throws IOException, InterruptedException { + return this.platformClient.deleteOldSecurityIdentities(securityProviderId, batchDelete); + } - /** - * Adds or updates an individual item in a push source. See [Adding a Single Item in a Push Source](https://docs.coveo.com/en/133). - * - * @param sourceId - * @param docBuilder - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse addOrUpdateDocument(String sourceId, DocumentBuilder docBuilder) throws IOException, InterruptedException { - CompressionType compressionType = docBuilder.getDocument().compressedBinaryData != null ? docBuilder.getDocument().compressedBinaryData.getCompressionType() : CompressionType.UNCOMPRESSED; - return this.platformClient.pushDocument(sourceId, docBuilder.marshal(), docBuilder.getDocument().uri, compressionType); - } + /** + * Manage batches of security identities. See [Manage Batches of Security + * Identities](https://docs.coveo.com/en/55). + * + * @param securityProviderId + * @param batchConfig + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse manageSecurityIdentities( + String securityProviderId, SecurityIdentityBatchConfig batchConfig) + throws IOException, InterruptedException { + return this.platformClient.manageSecurityIdentities(securityProviderId, batchConfig); + } - /** - * Deletes a specific item from a Push source. Optionally, the child items of that item can also be deleted. See [Deleting an Item in a Push Source](https://docs.coveo.com/en/171). - * - * @param sourceId - * @param documentId - * @param deleteChildren - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse deleteDocument(String sourceId, String documentId, Boolean deleteChildren) throws IOException, InterruptedException { - return this.platformClient.deleteDocument(sourceId, documentId, deleteChildren); - } + /** + * Adds or updates an individual item in a push source. See [Adding a Single Item in a Push + * Source](https://docs.coveo.com/en/133). + * + * @param sourceId + * @param docBuilder + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse addOrUpdateDocument(String sourceId, DocumentBuilder docBuilder) + throws IOException, InterruptedException { + CompressionType compressionType = + docBuilder.getDocument().compressedBinaryData != null + ? docBuilder.getDocument().compressedBinaryData.getCompressionType() + : CompressionType.UNCOMPRESSED; + return this.platformClient.pushDocument( + sourceId, docBuilder.marshal(), docBuilder.getDocument().uri, compressionType); + } - /** - * Manage batches of items in a push source. See [Manage Batches of Items in a Push Source](https://docs.coveo.com/en/90) - * - * @param sourceId - * @param batchUpdate - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse batchUpdateDocuments(String sourceId, BatchUpdate batchUpdate) throws IOException, InterruptedException { - HttpResponse resFileContainer = this.platformClient.createFileContainer(); - FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); - this.platformClient.uploadContentToFileContainer(fileContainer, new Gson().toJson(batchUpdate.marshal())); - return this.platformClient.pushFileContainerContent(sourceId, fileContainer); - } + /** + * Deletes a specific item from a Push source. Optionally, the child items of that item can also + * be deleted. See [Deleting an Item in a Push Source](https://docs.coveo.com/en/171). + * + * @param sourceId + * @param documentId + * @param deleteChildren + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse deleteDocument( + String sourceId, String documentId, Boolean deleteChildren) + throws IOException, InterruptedException { + return this.platformClient.deleteDocument(sourceId, documentId, deleteChildren); + } - /** - * Manages pushing batches of Security Identities to a File Container, then into Coveo. See [Manage Batches of Security Identities](https://docs.coveo.com/en/55) - * - * @param securityProviderId - * @param batchIdentity - * @return - * @throws IOException - * @throws InterruptedException - */ - public SecurityIdentityBatchResponse batchUpdateSecurityIdentities(String securityProviderId, BatchIdentity batchIdentity) throws IOException, InterruptedException { - SecurityIdentityBatchResponse securityIdentityBatchResponse = new SecurityIdentityBatchResponse(); - HttpResponse resFileContainer = this.platformClient.createFileContainer(); - FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); - String batchIdJson = new Gson().toJson(batchIdentity.marshal()); - securityIdentityBatchResponse.s3Response = this.platformClient.uploadContentToFileContainer(fileContainer, batchIdJson); - if (securityIdentityBatchResponse.s3Response.statusCode() >= 200 && securityIdentityBatchResponse.s3Response.statusCode() <= 299) { //maybe just 200 or 202 - SecurityIdentityBatchConfig batchConfig = new SecurityIdentityBatchConfig(fileContainer.fileId, 0l); - securityIdentityBatchResponse.batchResponse = this.manageSecurityIdentities(securityProviderId, batchConfig); - } - return securityIdentityBatchResponse; - } + /** + * Manage batches of items in a push source. See [Manage Batches of Items in a Push + * Source](https://docs.coveo.com/en/90) + * + * @param sourceId + * @param batchUpdate + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse batchUpdateDocuments(String sourceId, BatchUpdate batchUpdate) + throws IOException, InterruptedException { + HttpResponse resFileContainer = this.platformClient.createFileContainer(); + FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); + this.platformClient.uploadContentToFileContainer( + fileContainer, new Gson().toJson(batchUpdate.marshal())); + return this.platformClient.pushFileContainerContent(sourceId, fileContainer); + } - /** - * Creates a File Container. [Creating a File Container](https://docs.coveo.com/en/43) - * - * @return - * @throws IOException - * @throws InterruptedException - */ - public FileContainer createFileContainer() throws IOException, InterruptedException { - HttpResponse resFileContainer = this.platformClient.createFileContainer(); - return new Gson().fromJson(resFileContainer.body(), FileContainer.class); + /** + * Manages pushing batches of Security Identities to a File Container, then into Coveo. See + * [Manage Batches of Security Identities](https://docs.coveo.com/en/55) + * + * @param securityProviderId + * @param batchIdentity + * @return + * @throws IOException + * @throws InterruptedException + */ + public SecurityIdentityBatchResponse batchUpdateSecurityIdentities( + String securityProviderId, BatchIdentity batchIdentity) + throws IOException, InterruptedException { + SecurityIdentityBatchResponse securityIdentityBatchResponse = + new SecurityIdentityBatchResponse(); + HttpResponse resFileContainer = this.platformClient.createFileContainer(); + FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); + String batchIdJson = new Gson().toJson(batchIdentity.marshal()); + securityIdentityBatchResponse.s3Response = + this.platformClient.uploadContentToFileContainer(fileContainer, batchIdJson); + if (securityIdentityBatchResponse.s3Response.statusCode() >= 200 + && securityIdentityBatchResponse.s3Response.statusCode() <= 299) { // maybe just 200 or 202 + SecurityIdentityBatchConfig batchConfig = + new SecurityIdentityBatchConfig(fileContainer.fileId, 0l); + securityIdentityBatchResponse.batchResponse = + this.manageSecurityIdentities(securityProviderId, batchConfig); } + return securityIdentityBatchResponse; + } - /** - * Push file to a File Container. [Using the compressedBinaryDataFileId Property](https://docs.coveo.com/en/69) - * - * @param fileContainer - * @param fileAsBytes - * @return - * @throws IOException - * @throws InterruptedException - */ - public HttpResponse pushBinaryToFileContainer(FileContainer fileContainer, byte[] fileAsBytes) throws IOException, InterruptedException { - return this.platformClient.pushBinaryToFileContainer(fileContainer, fileAsBytes); - } + /** + * Creates a File Container. [Creating a File Container](https://docs.coveo.com/en/43) + * + * @return + * @throws IOException + * @throws InterruptedException + */ + public FileContainer createFileContainer() throws IOException, InterruptedException { + HttpResponse resFileContainer = this.platformClient.createFileContainer(); + return new Gson().fromJson(resFileContainer.body(), FileContainer.class); + } + + /** + * Push file to a File Container. [Using the compressedBinaryDataFileId + * Property](https://docs.coveo.com/en/69) + * + * @param fileContainer + * @param fileAsBytes + * @return + * @throws IOException + * @throws InterruptedException + */ + public HttpResponse pushBinaryToFileContainer( + FileContainer fileContainer, byte[] fileAsBytes) throws IOException, InterruptedException { + return this.platformClient.pushBinaryToFileContainer(fileContainer, fileAsBytes); + } } diff --git a/src/main/java/com/coveo/pushapiclient/SourceType.java b/src/main/java/com/coveo/pushapiclient/SourceType.java index 3251aa46..d587dcaf 100644 --- a/src/main/java/com/coveo/pushapiclient/SourceType.java +++ b/src/main/java/com/coveo/pushapiclient/SourceType.java @@ -1,39 +1,42 @@ package com.coveo.pushapiclient; -public enum SourceType implements SourceTypeInterface{ - PUSH{ - public String toString() { - return "PUSH"; - } - public boolean isPushEnabled(){ return true;} - - @Override - public boolean isStreamEnabled() { - return false; - } - - }, - CATALOG{ - public String toString() { - return "CATALOG"; - } - - @Override - public boolean isPushEnabled() { - return true; - } - - @Override - public boolean isStreamEnabled() { - return true; - } - }, +public enum SourceType implements SourceTypeInterface { + PUSH { + public String toString() { + return "PUSH"; + } + + public boolean isPushEnabled() { + return true; + } + + @Override + public boolean isStreamEnabled() { + return false; + } + }, + CATALOG { + public String toString() { + return "CATALOG"; + } + + @Override + public boolean isPushEnabled() { + return true; + } + + @Override + public boolean isStreamEnabled() { + return true; + } + }, } interface SourceTypeInterface { - String toString(); - boolean isPushEnabled(); - boolean isStreamEnabled(); + String toString(); + boolean isPushEnabled(); + + boolean isStreamEnabled(); } diff --git a/src/main/java/com/coveo/pushapiclient/SourceVisibility.java b/src/main/java/com/coveo/pushapiclient/SourceVisibility.java index 416a1233..bedaa299 100644 --- a/src/main/java/com/coveo/pushapiclient/SourceVisibility.java +++ b/src/main/java/com/coveo/pushapiclient/SourceVisibility.java @@ -1,31 +1,26 @@ package com.coveo.pushapiclient; /** - * SourceVisibility controls the content security option that should be applied to the items in a source. See https://docs.coveo.com/en/1779/index-content/content-security + * SourceVisibility controls the content security option that should be applied to the items in a + * source. See https://docs.coveo.com/en/1779/index-content/content-security */ public enum SourceVisibility { - /** - * Items can be accessed by the source owner only. - */ - PRIVATE { - public String toString() { - return "PRIVATE"; - } - }, - /** - * Items can be accessed by allowed users only. - */ - SECURED { - public String toString() { - return "SECURED"; - } - }, - /** - * Items can be accessed by any user. - */ - SHARED { - public String toString() { - return "SHARED"; - } + /** Items can be accessed by the source owner only. */ + PRIVATE { + public String toString() { + return "PRIVATE"; } + }, + /** Items can be accessed by allowed users only. */ + SECURED { + public String toString() { + return "SECURED"; + } + }, + /** Items can be accessed by any user. */ + SHARED { + public String toString() { + return "SHARED"; + } + } } diff --git a/src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java b/src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java index b04912bf..a35e1be9 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java +++ b/src/main/java/com/coveo/pushapiclient/StreamEnabledSource.java @@ -1,6 +1,4 @@ package com.coveo.pushapiclient; // Marker Interface -public interface StreamEnabledSource extends BaseSource { - -} +public interface StreamEnabledSource extends BaseSource {} diff --git a/src/main/java/com/coveo/pushapiclient/StreamResponse.java b/src/main/java/com/coveo/pushapiclient/StreamResponse.java index 61f2ceb7..af0015c9 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamResponse.java +++ b/src/main/java/com/coveo/pushapiclient/StreamResponse.java @@ -3,9 +3,8 @@ import java.util.Map; public class StreamResponse { - public String uploadUri; - public String fileId; - public String streamId; - public Map requiredHeaders; - + public String uploadUri; + public String fileId; + public String streamId; + public Map requiredHeaders; } diff --git a/src/main/java/com/coveo/pushapiclient/StreamService.java b/src/main/java/com/coveo/pushapiclient/StreamService.java index b9212e20..a536ded4 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamService.java +++ b/src/main/java/com/coveo/pushapiclient/StreamService.java @@ -1,116 +1,112 @@ package com.coveo.pushapiclient; -import java.io.IOException; -import java.net.http.HttpResponse; - import com.coveo.pushapiclient.exceptions.NoOpenStreamException; import com.google.gson.Gson; +import java.io.IOException; +import java.net.http.HttpResponse; // TODO: LENS-851 - Make public class StreamService { - private final StreamEnabledSource source; - private final PlatformClient platformClient; - private StreamServiceInternal service; - private String streamId; - private DocumentUploadQueue queue; - - /** - * Creates a service to stream your documents to the provided source by - * interacting with the Stream API. - * - *

- * To perform full document - * updates, use the {@PushService}, since pushing documents with the - * {@StreamService} is equivalent to triggering a full source rebuild. The - * {@StreamService} can also be used for an initial catalog upload. - * - * @param source The source to which you want to send your documents. - */ - public StreamService(StreamEnabledSource source) { - String apiKey = source.getApiKey(); - String organizationId = source.getOrganizationId(); - PlatformUrl platformUrl = source.getPlatformUrl(); - UploadStrategy uploader = this.getUploadStrategy(); - - this.source = source; - this.queue = new DocumentUploadQueue(uploader); - this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); - this.service = new StreamServiceInternal(this.source, this.queue, this.platformClient); - } + private final StreamEnabledSource source; + private final PlatformClient platformClient; + private StreamServiceInternal service; + private String streamId; + private DocumentUploadQueue queue; - /** - * Adds documents to the previously specified source. - * This function will open a stream before uploading documents into it. - * - *

- * If called several times, the service will automatically batch documents and - * create new stream chunks whenever the data payload exceeds the - * batch size limit - * set for the Stream API. - * - *

- * Once there are no more documents to add, it is important to call the {@link StreamService#close} function - * in order to send any buffered documents and close the open stream. - * Otherwise, changes will not be reflected in the index. - * - *

- *

-     * {@code
-     * //...
-     * StreamService service = new StreamService(source));
-     * for (DocumentBuilder document : fictionalDocumentList) {
-     *     service.add(document);
-     * }
-     * service.close(document);
-     * 
- * - *

- * For more code samples, visit Stream data to your catalog source - * - * @param document The documentBuilder to add to your source - * @throws InterruptedException - * @throws IOException - */ - public void add(DocumentBuilder document) throws IOException, InterruptedException { - this.service.add(document); - } + /** + * Creates a service to stream your documents to the provided source by interacting with the + * Stream API. + * + *

To perform full document updates, use the + * {@PushService}, since pushing documents with the {@StreamService} is equivalent to triggering a + * full source rebuild. The {@StreamService} can also be used for an initial catalog upload. + * + * @param source The source to which you want to send your documents. + */ + public StreamService(StreamEnabledSource source) { + String apiKey = source.getApiKey(); + String organizationId = source.getOrganizationId(); + PlatformUrl platformUrl = source.getPlatformUrl(); + UploadStrategy uploader = this.getUploadStrategy(); - /** - * Sends any buffered documents and closes the stream. - * - *

- * Upon invoking this method, any indexed items not added through this {@link StreamService} instance will be removed. - * All documents added from the initialization of the service until the invocation of the {@link StreamService#close} function - * will completely replace the previous content of the source. - * - *

- * When you upload a catalog into a source, it will replace the previous content - * of the source completely. Expect a 15-minute delay for the removal of the old - * items from the index. - * - * @return - * @throws IOException - * @throws InterruptedException - * @throws NoOpenStreamException - */ - public HttpResponse close() throws IOException, InterruptedException, NoOpenStreamException { - return this.service.close(); - } + this.source = source; + this.queue = new DocumentUploadQueue(uploader); + this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); + this.service = new StreamServiceInternal(this.source, this.queue, this.platformClient); + } - private UploadStrategy getUploadStrategy() { - return (batchUpdate) -> { - String sourceId = this.getSourceId(); - HttpResponse resFileContainer = this.platformClient.requireStreamChunk(sourceId, this.streamId); - FileContainer fileContainer = new Gson().fromJson(resFileContainer.body(), FileContainer.class); - String batchUpdateJson = new Gson().toJson(batchUpdate.marshal()); - return this.platformClient.uploadContentToFileContainer(fileContainer, - batchUpdateJson); + /** + * Adds documents to the previously specified source. + * This function will open a stream before uploading documents into it. + * + *

+ * If called several times, the service will automatically batch documents and + * create new stream chunks whenever the data payload exceeds the + * batch size limit + * set for the Stream API. + * + *

+ * Once there are no more documents to add, it is important to call the {@link StreamService#close} function + * in order to send any buffered documents and close the open stream. + * Otherwise, changes will not be reflected in the index. + * + *

+ *

+   * {@code
+   * //...
+   * StreamService service = new StreamService(source));
+   * for (DocumentBuilder document : fictionalDocumentList) {
+   *     service.add(document);
+   * }
+   * service.close(document);
+   * 
+ * + *

+ * For more code samples, visit Stream data to your catalog source + * + * @param document The documentBuilder to add to your source + * @throws InterruptedException + * @throws IOException + */ + public void add(DocumentBuilder document) throws IOException, InterruptedException { + this.service.add(document); + } - }; - } + /** + * Sends any buffered documents and closes the stream. + * + *

Upon invoking this method, any indexed items not added through this {@link StreamService} + * instance will be removed. All documents added from the initialization of the service until the + * invocation of the {@link StreamService#close} function will completely replace the previous + * content of the source. + * + *

When you upload a catalog into a source, it will replace the previous content of the source + * completely. Expect a 15-minute delay for the removal of the old items from the index. + * + * @return + * @throws IOException + * @throws InterruptedException + * @throws NoOpenStreamException + */ + public HttpResponse close() + throws IOException, InterruptedException, NoOpenStreamException { + return this.service.close(); + } - private String getSourceId() { - return this.source.getId(); - } + private UploadStrategy getUploadStrategy() { + return (batchUpdate) -> { + String sourceId = this.getSourceId(); + HttpResponse resFileContainer = + this.platformClient.requireStreamChunk(sourceId, this.streamId); + FileContainer fileContainer = + new Gson().fromJson(resFileContainer.body(), FileContainer.class); + String batchUpdateJson = new Gson().toJson(batchUpdate.marshal()); + return this.platformClient.uploadContentToFileContainer(fileContainer, batchUpdateJson); + }; + } + private String getSourceId() { + return this.source.getId(); + } } diff --git a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java index 81f47c85..b0145504 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java +++ b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java @@ -1,52 +1,50 @@ package com.coveo.pushapiclient; -import java.io.IOException; -import java.net.http.HttpResponse; - import com.coveo.pushapiclient.exceptions.NoOpenStreamException; import com.google.gson.Gson; +import java.io.IOException; +import java.net.http.HttpResponse; -/** - * For internal use only. Made to easily test the service without having to use PowerMock - */ +/** For internal use only. Made to easily test the service without having to use PowerMock */ class StreamServiceInternal { - private final StreamEnabledSource source; - private final PlatformClient platformClient; - private String streamId; - private DocumentUploadQueue queue; - - public StreamServiceInternal(StreamEnabledSource source, DocumentUploadQueue queue, PlatformClient platformClient) { - this.source = source; - this.queue = queue; - this.platformClient = platformClient; - } - - public void add(DocumentBuilder document) throws IOException, InterruptedException { - if (this.streamId == null) { - this.streamId = this.getStreamId(); - } - queue.add(document); - } - - public HttpResponse close() throws IOException, InterruptedException, NoOpenStreamException { - if (this.streamId == null) { - throw new NoOpenStreamException( - "No open stream detected. A stream will automatically be opened once you start adding documents."); - } - queue.flush(); - String sourceId = this.getSourceId(); - return this.platformClient.closeStream(sourceId, this.streamId); + private final StreamEnabledSource source; + private final PlatformClient platformClient; + private String streamId; + private DocumentUploadQueue queue; + + public StreamServiceInternal( + StreamEnabledSource source, DocumentUploadQueue queue, PlatformClient platformClient) { + this.source = source; + this.queue = queue; + this.platformClient = platformClient; + } + + public void add(DocumentBuilder document) throws IOException, InterruptedException { + if (this.streamId == null) { + this.streamId = this.getStreamId(); } - - private String getStreamId() throws IOException, InterruptedException { - String sourceId = this.getSourceId(); - HttpResponse response = this.platformClient.openStream(sourceId); - StreamResponse streamResponse = new Gson().fromJson(response.body(), StreamResponse.class); - return streamResponse.streamId; + queue.add(document); + } + + public HttpResponse close() + throws IOException, InterruptedException, NoOpenStreamException { + if (this.streamId == null) { + throw new NoOpenStreamException( + "No open stream detected. A stream will automatically be opened once you start adding documents."); } - - private String getSourceId() { - return this.source.getId(); - } - + queue.flush(); + String sourceId = this.getSourceId(); + return this.platformClient.closeStream(sourceId, this.streamId); + } + + private String getStreamId() throws IOException, InterruptedException { + String sourceId = this.getSourceId(); + HttpResponse response = this.platformClient.openStream(sourceId); + StreamResponse streamResponse = new Gson().fromJson(response.body(), StreamResponse.class); + return streamResponse.streamId; + } + + private String getSourceId() { + return this.source.getId(); + } } diff --git a/src/main/java/com/coveo/pushapiclient/UploadStrategy.java b/src/main/java/com/coveo/pushapiclient/UploadStrategy.java index e77dd01c..053f7ba6 100644 --- a/src/main/java/com/coveo/pushapiclient/UploadStrategy.java +++ b/src/main/java/com/coveo/pushapiclient/UploadStrategy.java @@ -5,5 +5,5 @@ @FunctionalInterface public interface UploadStrategy { - HttpResponse apply(BatchUpdate batchUpdate) throws IOException, InterruptedException; + HttpResponse apply(BatchUpdate batchUpdate) throws IOException, InterruptedException; } diff --git a/src/main/java/com/coveo/pushapiclient/UserSecurityIdentityBuilder.java b/src/main/java/com/coveo/pushapiclient/UserSecurityIdentityBuilder.java index 5caa6486..d713df49 100644 --- a/src/main/java/com/coveo/pushapiclient/UserSecurityIdentityBuilder.java +++ b/src/main/java/com/coveo/pushapiclient/UserSecurityIdentityBuilder.java @@ -5,82 +5,90 @@ /** * Build a security identity of type `USER`. - *

- * Typically used in conjunction with {@link DocumentBuilder#withAllowedPermissions} or {@link DocumentBuilder#withDeniedPermissions}. - *

- * See {@link SecurityIdentity}. + * + *

Typically used in conjunction with {@link DocumentBuilder#withAllowedPermissions} or {@link + * DocumentBuilder#withDeniedPermissions}. + * + *

See {@link SecurityIdentity}. */ public class UserSecurityIdentityBuilder implements SecurityIdentityBuilder { - private final String[] identities; - private final String securityProvider; + private final String[] identities; + private final String securityProvider; - public UserSecurityIdentityBuilder(String[] identities, String securityProvider) { - this.identities = identities; - this.securityProvider = securityProvider; - } + public UserSecurityIdentityBuilder(String[] identities, String securityProvider) { + this.identities = identities; + this.securityProvider = securityProvider; + } - /** - * Construct a UserSecurityIdentityBuilder for a single identity with the given security provider. - * - * @param identity - * @param securityProvider - */ - public UserSecurityIdentityBuilder(String identity, String securityProvider) { - this(new String[]{identity}, securityProvider); - } + /** + * Construct a UserSecurityIdentityBuilder for a single identity with the given security provider. + * + * @param identity + * @param securityProvider + */ + public UserSecurityIdentityBuilder(String identity, String securityProvider) { + this(new String[] {identity}, securityProvider); + } - /** - * Construct a UserSecurityIdentityBuilder for a single identity with an `Email Security Provider`. - * - * @param identity - */ - public UserSecurityIdentityBuilder(String identity) { - this(new String[]{identity}, "Email Security Provider"); - } + /** + * Construct a UserSecurityIdentityBuilder for a single identity with an `Email Security + * Provider`. + * + * @param identity + */ + public UserSecurityIdentityBuilder(String identity) { + this(new String[] {identity}, "Email Security Provider"); + } - /** - * Construct a UserSecurityIdentityBuilder for multiple identities with an `Email Security Provider`. - * - * @param identities - */ - public UserSecurityIdentityBuilder(String[] identities) { - this(identities, "Email Security Provider"); - } + /** + * Construct a UserSecurityIdentityBuilder for multiple identities with an `Email Security + * Provider`. + * + * @param identities + */ + public UserSecurityIdentityBuilder(String[] identities) { + this(identities, "Email Security Provider"); + } + public SecurityIdentity[] build() { + return new AnySecurityIdentityBuilder( + this.identities, SecurityIdentityType.USER, this.securityProvider) + .build(); + } - public SecurityIdentity[] build() { - return new AnySecurityIdentityBuilder(this.identities, SecurityIdentityType.USER, this.securityProvider).build(); - } + public String[] getIdentities() { + return identities; + } - public String[] getIdentities() { - return identities; - } + public String getSecurityProvider() { + return securityProvider; + } - public String getSecurityProvider() { - return securityProvider; - } + @Override + public String toString() { + return "UserSecurityIdentityBuilder[" + + "identities=" + + Arrays.toString(identities) + + ", securityProvider='" + + securityProvider + + '\'' + + ']'; + } - @Override - public String toString() { - return "UserSecurityIdentityBuilder[" + - "identities=" + Arrays.toString(identities) + - ", securityProvider='" + securityProvider + '\'' + - ']'; - } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + UserSecurityIdentityBuilder that = (UserSecurityIdentityBuilder) obj; + return Arrays.equals(identities, that.identities) + && Objects.equals(securityProvider, that.securityProvider); + } - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - UserSecurityIdentityBuilder that = (UserSecurityIdentityBuilder) obj; - return Arrays.equals(identities, that.identities) && Objects.equals(securityProvider, that.securityProvider); - } - - @Override - public int hashCode() { - int result = Objects.hash(securityProvider); - result = 31 * result + Arrays.hashCode(identities); - return result; - } + @Override + public int hashCode() { + int result = Objects.hash(securityProvider); + result = 31 * result + Arrays.hashCode(identities); + return result; + } } diff --git a/src/main/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilder.java b/src/main/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilder.java index a61636ae..c6cc427e 100644 --- a/src/main/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilder.java +++ b/src/main/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilder.java @@ -5,64 +5,70 @@ /** * Build a security identity of type `VIRTUAL_GROUP`. - *

- * Typically used in conjunction with {@link DocumentBuilder#withAllowedPermissions} or {@link DocumentBuilder#withDeniedPermissions}. - *

- * See {@link SecurityIdentity}. + * + *

Typically used in conjunction with {@link DocumentBuilder#withAllowedPermissions} or {@link + * DocumentBuilder#withDeniedPermissions}. + * + *

See {@link SecurityIdentity}. */ public class VirtualGroupSecurityIdentityBuilder implements SecurityIdentityBuilder { - private final String[] identities; - private final String securityProvider; + private final String[] identities; + private final String securityProvider; - public VirtualGroupSecurityIdentityBuilder(String[] identities, String securityProvider) { - this.identities = identities; - this.securityProvider = securityProvider; - } + public VirtualGroupSecurityIdentityBuilder(String[] identities, String securityProvider) { + this.identities = identities; + this.securityProvider = securityProvider; + } - /** - * Construct a VirtualGroupSecurityIdentityBuilder with a single identity. - * - * @param identity - * @param securityProvider - */ - public VirtualGroupSecurityIdentityBuilder(String identity, String securityProvider) { - this(new String[]{identity}, securityProvider); - } + /** + * Construct a VirtualGroupSecurityIdentityBuilder with a single identity. + * + * @param identity + * @param securityProvider + */ + public VirtualGroupSecurityIdentityBuilder(String identity, String securityProvider) { + this(new String[] {identity}, securityProvider); + } - public SecurityIdentity[] build() { - return new AnySecurityIdentityBuilder(this.identities, SecurityIdentityType.VIRTUAL_GROUP, this.securityProvider).build(); - } + public SecurityIdentity[] build() { + return new AnySecurityIdentityBuilder( + this.identities, SecurityIdentityType.VIRTUAL_GROUP, this.securityProvider) + .build(); + } - public String[] getIdentities() { - return identities; - } + public String[] getIdentities() { + return identities; + } - public String getSecurityProvider() { - return securityProvider; - } + public String getSecurityProvider() { + return securityProvider; + } - @Override - public String toString() { - return "VirtualGroupSecurityIdentityBuilder[" + - "identities=" + Arrays.toString(identities) + - ", securityProvider='" + securityProvider + '\'' + - ']'; - } + @Override + public String toString() { + return "VirtualGroupSecurityIdentityBuilder[" + + "identities=" + + Arrays.toString(identities) + + ", securityProvider='" + + securityProvider + + '\'' + + ']'; + } - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - VirtualGroupSecurityIdentityBuilder that = (VirtualGroupSecurityIdentityBuilder) obj; - return Arrays.equals(identities, that.identities) && Objects.equals(securityProvider, that.securityProvider); - } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + VirtualGroupSecurityIdentityBuilder that = (VirtualGroupSecurityIdentityBuilder) obj; + return Arrays.equals(identities, that.identities) + && Objects.equals(securityProvider, that.securityProvider); + } - @Override - public int hashCode() { - int result = Objects.hash(securityProvider); - result = 31 * result + Arrays.hashCode(identities); - return result; - } + @Override + public int hashCode() { + int result = Objects.hash(securityProvider); + result = 31 * result + Arrays.hashCode(identities); + return result; + } } - diff --git a/src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java b/src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java index 91b2cf3a..18489ec4 100644 --- a/src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java +++ b/src/main/java/com/coveo/pushapiclient/exceptions/NoOpenStreamException.java @@ -1,7 +1,7 @@ package com.coveo.pushapiclient.exceptions; public class NoOpenStreamException extends Exception { - public NoOpenStreamException(String errorMessage) { - super(errorMessage); - } + public NoOpenStreamException(String errorMessage) { + super(errorMessage); + } } diff --git a/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java b/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java index 964dcb55..c1440b5d 100644 --- a/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java +++ b/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java @@ -4,84 +4,98 @@ import java.net.MalformedURLException; import java.net.URL; - import org.junit.Test; public class ApiUrlTest { - @Test - public void testSourceId() throws MalformedURLException { - ApiUrl url = new ApiUrl( - new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - assertEquals(url.getSourceId(), "my-source-id"); - } - - @Test - public void testOrganizationId() throws MalformedURLException { - ApiUrl url = new ApiUrl( - new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - assertEquals(url.getOrganizationId(), "my-org-id"); - } - - @Test - public void testPlatformUrl() throws MalformedURLException { - ApiUrl defaultUrl = new ApiUrl( - new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - ApiUrl regionOnlyUrl = new ApiUrl( - new URL("https://api-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - ApiUrl environmentOnlyUrl = new ApiUrl( - new URL("https://apidev.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - ApiUrl environmentAndRegionUrl = new ApiUrl( - new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - - assertEquals(defaultUrl.getPlatformUrl().getApiUrl(), "https://api.cloud.coveo.com"); - assertEquals(regionOnlyUrl.getPlatformUrl().getApiUrl(), "https://api-au.cloud.coveo.com"); - assertEquals(environmentOnlyUrl.getPlatformUrl().getApiUrl(), "https://apidev.cloud.coveo.com"); - assertEquals(environmentAndRegionUrl.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); - } - - @Test - public void testStreamApiUrl() throws MalformedURLException { - ApiUrl url = new ApiUrl( - new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/stream/open")); - - assertEquals(url.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); - assertEquals(url.getOrganizationId(), "my-org-id"); - assertEquals(url.getSourceId(), "my-source-id"); - } - - @Test(expected = MalformedURLException.class) - public void testInvalidEnvironmentUrl() throws MalformedURLException { + @Test + public void testSourceId() throws MalformedURLException { + ApiUrl url = new ApiUrl( - new URL("https://apifoo.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - - } - @Test(expected = MalformedURLException.class) - public void testInvalidUrl() throws MalformedURLException { + new URL( + "https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + assertEquals(url.getSourceId(), "my-source-id"); + } + + @Test + public void testOrganizationId() throws MalformedURLException { + ApiUrl url = new ApiUrl( - new URL("https://apifoo.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - - } - - @Test(expected = MalformedURLException.class) - public void testInvalidRegionUrl() throws MalformedURLException { + new URL( + "https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + assertEquals(url.getOrganizationId(), "my-org-id"); + } + + @Test + public void testPlatformUrl() throws MalformedURLException { + ApiUrl defaultUrl = new ApiUrl( - new URL( - "https://api-bar.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - - } - - @Test(expected = MalformedURLException.class) - public void testInvalidPathUrl() throws MalformedURLException { + new URL( + "https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + ApiUrl regionOnlyUrl = new ApiUrl( - new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/providers/provider-id/mappings")); - - } - - @Test(expected = MalformedURLException.class) - public void testInvalidHostUrl() throws MalformedURLException { + new URL( + "https://api-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + ApiUrl environmentOnlyUrl = new ApiUrl( - new URL("https://platform.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - - } + new URL( + "https://apidev.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + ApiUrl environmentAndRegionUrl = + new ApiUrl( + new URL( + "https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + + assertEquals(defaultUrl.getPlatformUrl().getApiUrl(), "https://api.cloud.coveo.com"); + assertEquals(regionOnlyUrl.getPlatformUrl().getApiUrl(), "https://api-au.cloud.coveo.com"); + assertEquals(environmentOnlyUrl.getPlatformUrl().getApiUrl(), "https://apidev.cloud.coveo.com"); + assertEquals( + environmentAndRegionUrl.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); + } + + @Test + public void testStreamApiUrl() throws MalformedURLException { + ApiUrl url = + new ApiUrl( + new URL( + "https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/stream/open")); + + assertEquals(url.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); + assertEquals(url.getOrganizationId(), "my-org-id"); + assertEquals(url.getSourceId(), "my-source-id"); + } + + @Test(expected = MalformedURLException.class) + public void testInvalidEnvironmentUrl() throws MalformedURLException { + new ApiUrl( + new URL( + "https://apifoo.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + } + + @Test(expected = MalformedURLException.class) + public void testInvalidUrl() throws MalformedURLException { + new ApiUrl( + new URL( + "https://apifoo.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + } + + @Test(expected = MalformedURLException.class) + public void testInvalidRegionUrl() throws MalformedURLException { + new ApiUrl( + new URL( + "https://api-bar.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + } + + @Test(expected = MalformedURLException.class) + public void testInvalidPathUrl() throws MalformedURLException { + new ApiUrl( + new URL( + "https://api.cloud.coveo.com/push/v1/organizations/my-org-id/providers/provider-id/mappings")); + } + + @Test(expected = MalformedURLException.class) + public void testInvalidHostUrl() throws MalformedURLException { + new ApiUrl( + new URL( + "https://platform.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + } } diff --git a/src/test/java/com/coveo/pushapiclient/BatchUpdateRecordTest.java b/src/test/java/com/coveo/pushapiclient/BatchUpdateRecordTest.java index fefb87d3..cae85d2e 100644 --- a/src/test/java/com/coveo/pushapiclient/BatchUpdateRecordTest.java +++ b/src/test/java/com/coveo/pushapiclient/BatchUpdateRecordTest.java @@ -1,62 +1,62 @@ package com.coveo.pushapiclient; +import static org.junit.Assert.*; + import com.google.gson.Gson; import com.google.gson.JsonObject; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - public class BatchUpdateRecordTest { - private BatchUpdateRecord bur1; - private BatchUpdateRecord bur2; - private BatchUpdateRecord bur3; - private BatchUpdateRecord bur4; - - @Before - public void setUp() throws Exception { - Gson gson = new Gson(); - JsonObject json1 = gson.fromJson("{ \"key\": \"value1\" }", JsonObject.class); - JsonObject json2 = gson.fromJson("{ \"key\": \"value1\" }", JsonObject.class); - JsonObject json3 = gson.fromJson("{ \"key3\": \"value3\" }", JsonObject.class); - JsonObject json4 = gson.fromJson("{ \"key4\": \"value4\" }", JsonObject.class); - - JsonObject[] jsonArray1 = new JsonObject[] {json1, json3}; - JsonObject[] jsonArray2 = new JsonObject[] {json2, json3}; - JsonObject[] jsonArray3 = new JsonObject[] {json1, json3}; - JsonObject[] jsonArray4 = new JsonObject[] {json4, json3}; - - bur1 = new BatchUpdateRecord(jsonArray1, jsonArray2); - bur2 = new BatchUpdateRecord(jsonArray1, jsonArray2); - bur3 = new BatchUpdateRecord(jsonArray3, jsonArray4); - bur4 = bur1; - } - - @Test - public void testToString() { - assertEquals(bur1.toString(), bur1.toString()); - assertEquals(bur1.toString(), bur2.toString()); - assertEquals(bur1.toString(), bur4.toString()); - assertNotEquals(bur1.toString(), bur3.toString()); - } - - @Test - public void testEquals() { - assertTrue(bur1.equals(bur1)); - assertTrue(bur1.equals(bur2)); - assertFalse(bur1.equals(bur3)); - assertTrue(bur1.equals(bur4)); - assertFalse(bur1.equals(null)); - } - - @Test - public void testHashCode() { - assertEquals(bur1.hashCode(), bur1.hashCode()); - assertEquals(bur1.hashCode(), bur2.hashCode()); - assertEquals(bur1.hashCode(), bur4.hashCode()); - assertEquals(bur3.hashCode(), bur3.hashCode()); - assertNotEquals(bur1.hashCode(), bur3.hashCode()); - assertNotEquals(bur2.hashCode(), bur3.hashCode()); - } -} \ No newline at end of file + private BatchUpdateRecord bur1; + private BatchUpdateRecord bur2; + private BatchUpdateRecord bur3; + private BatchUpdateRecord bur4; + + @Before + public void setUp() throws Exception { + Gson gson = new Gson(); + JsonObject json1 = gson.fromJson("{ \"key\": \"value1\" }", JsonObject.class); + JsonObject json2 = gson.fromJson("{ \"key\": \"value1\" }", JsonObject.class); + JsonObject json3 = gson.fromJson("{ \"key3\": \"value3\" }", JsonObject.class); + JsonObject json4 = gson.fromJson("{ \"key4\": \"value4\" }", JsonObject.class); + + JsonObject[] jsonArray1 = new JsonObject[] {json1, json3}; + JsonObject[] jsonArray2 = new JsonObject[] {json2, json3}; + JsonObject[] jsonArray3 = new JsonObject[] {json1, json3}; + JsonObject[] jsonArray4 = new JsonObject[] {json4, json3}; + + bur1 = new BatchUpdateRecord(jsonArray1, jsonArray2); + bur2 = new BatchUpdateRecord(jsonArray1, jsonArray2); + bur3 = new BatchUpdateRecord(jsonArray3, jsonArray4); + bur4 = bur1; + } + + @Test + public void testToString() { + assertEquals(bur1.toString(), bur1.toString()); + assertEquals(bur1.toString(), bur2.toString()); + assertEquals(bur1.toString(), bur4.toString()); + assertNotEquals(bur1.toString(), bur3.toString()); + } + + @Test + public void testEquals() { + assertTrue(bur1.equals(bur1)); + assertTrue(bur1.equals(bur2)); + assertFalse(bur1.equals(bur3)); + assertTrue(bur1.equals(bur4)); + assertFalse(bur1.equals(null)); + } + + @Test + public void testHashCode() { + assertEquals(bur1.hashCode(), bur1.hashCode()); + assertEquals(bur1.hashCode(), bur2.hashCode()); + assertEquals(bur1.hashCode(), bur4.hashCode()); + assertEquals(bur3.hashCode(), bur3.hashCode()); + assertNotEquals(bur1.hashCode(), bur3.hashCode()); + assertNotEquals(bur2.hashCode(), bur3.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/BatchUpdateTest.java b/src/test/java/com/coveo/pushapiclient/BatchUpdateTest.java index e7383bf9..26f25e40 100644 --- a/src/test/java/com/coveo/pushapiclient/BatchUpdateTest.java +++ b/src/test/java/com/coveo/pushapiclient/BatchUpdateTest.java @@ -1,83 +1,82 @@ package com.coveo.pushapiclient; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; -public class BatchUpdateTest { - - private BatchUpdate batch1; - private BatchUpdate batch2; - private BatchUpdate batch3; - private BatchUpdate batch4; - - @Before - public void setUp() { - DocumentBuilder db1 = new DocumentBuilder("some_uri", "some_title"); - DocumentBuilder db2 = new DocumentBuilder("some_uri", "some_title"); - DocumentBuilder db3 = new DocumentBuilder("some_other_uri", "some_title"); - DocumentBuilder db4 = new DocumentBuilder("some_uri", "some_other_title"); - - List list1 = new ArrayList<>(); - list1.add(db1); - list1.add(db3); - - List list2 = new ArrayList<>(); - list2.add(db1); - list2.add(db4); - - List list3 = new ArrayList<>(); - list3.add(db2); - list3.add(db3); - list3.add(db4); - - DeleteDocument del1 = new DeleteDocument("123"); - DeleteDocument del2 = new DeleteDocument("456"); - DeleteDocument del3 = new DeleteDocument("789"); - - List delList1 = new ArrayList<>(); - delList1.add(del1); - delList1.add(del2); - - List delList2 = new ArrayList<>(); - delList2.add(del2); - delList2.add(del3); - - batch1 = new BatchUpdate(list1, delList1); - batch2 = new BatchUpdate(list1, delList1); - batch3 = new BatchUpdate(list2, delList2); - batch4 = batch1; - } - - @Test - public void testToString() { - assertEquals(batch1.toString(), batch1.toString()); - assertEquals(batch1.toString(), batch2.toString()); - assertEquals(batch1.toString(), batch4.toString()); - assertNotEquals(batch1.toString(), batch3.toString()); - } +import java.util.ArrayList; +import java.util.List; +import org.junit.Before; +import org.junit.Test; - @Test - public void testEquals() { - assertFalse(batch1.equals(null)); - assertTrue(batch1.equals(batch1)); - assertTrue(batch1.equals(batch2)); - assertTrue(batch1.equals(batch4)); - assertFalse(batch1.equals(batch3)); - } +public class BatchUpdateTest { - @Test - public void testHashCode() { - assertEquals(batch1.hashCode(), batch1.hashCode()); - assertEquals(batch1.hashCode(), batch2.hashCode()); - assertEquals(batch1.hashCode(), batch4.hashCode()); - assertNotEquals(batch1.hashCode(), batch3.hashCode()); - } -} \ No newline at end of file + private BatchUpdate batch1; + private BatchUpdate batch2; + private BatchUpdate batch3; + private BatchUpdate batch4; + + @Before + public void setUp() { + DocumentBuilder db1 = new DocumentBuilder("some_uri", "some_title"); + DocumentBuilder db2 = new DocumentBuilder("some_uri", "some_title"); + DocumentBuilder db3 = new DocumentBuilder("some_other_uri", "some_title"); + DocumentBuilder db4 = new DocumentBuilder("some_uri", "some_other_title"); + + List list1 = new ArrayList<>(); + list1.add(db1); + list1.add(db3); + + List list2 = new ArrayList<>(); + list2.add(db1); + list2.add(db4); + + List list3 = new ArrayList<>(); + list3.add(db2); + list3.add(db3); + list3.add(db4); + + DeleteDocument del1 = new DeleteDocument("123"); + DeleteDocument del2 = new DeleteDocument("456"); + DeleteDocument del3 = new DeleteDocument("789"); + + List delList1 = new ArrayList<>(); + delList1.add(del1); + delList1.add(del2); + + List delList2 = new ArrayList<>(); + delList2.add(del2); + delList2.add(del3); + + batch1 = new BatchUpdate(list1, delList1); + batch2 = new BatchUpdate(list1, delList1); + batch3 = new BatchUpdate(list2, delList2); + batch4 = batch1; + } + + @Test + public void testToString() { + assertEquals(batch1.toString(), batch1.toString()); + assertEquals(batch1.toString(), batch2.toString()); + assertEquals(batch1.toString(), batch4.toString()); + assertNotEquals(batch1.toString(), batch3.toString()); + } + + @Test + public void testEquals() { + assertFalse(batch1.equals(null)); + assertTrue(batch1.equals(batch1)); + assertTrue(batch1.equals(batch2)); + assertTrue(batch1.equals(batch4)); + assertFalse(batch1.equals(batch3)); + } + + @Test + public void testHashCode() { + assertEquals(batch1.hashCode(), batch1.hashCode()); + assertEquals(batch1.hashCode(), batch2.hashCode()); + assertEquals(batch1.hashCode(), batch4.hashCode()); + assertNotEquals(batch1.hashCode(), batch3.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/CompressedBinaryDataTest.java b/src/test/java/com/coveo/pushapiclient/CompressedBinaryDataTest.java index 231307d9..df555f3b 100644 --- a/src/test/java/com/coveo/pushapiclient/CompressedBinaryDataTest.java +++ b/src/test/java/com/coveo/pushapiclient/CompressedBinaryDataTest.java @@ -1,55 +1,55 @@ package com.coveo.pushapiclient; +import static org.junit.Assert.*; + import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - public class CompressedBinaryDataTest { - private CompressedBinaryData data1; - private CompressedBinaryData data2; - - private CompressedBinaryData data3; - private CompressedBinaryData data4; - private CompressedBinaryData data5; - - @Before - public void setUp() { - data1 = new CompressedBinaryData("some_data", CompressionType.UNCOMPRESSED); - data2 = new CompressedBinaryData("some_data", CompressionType.UNCOMPRESSED); - - data3 = new CompressedBinaryData("some_other_data", CompressionType.UNCOMPRESSED); - data4 = new CompressedBinaryData("some_data", CompressionType.GZIP); - data5 = data1; - } - - @Test - public void testToString() { - assertEquals(data1.toString(), data1.toString()); - assertEquals(data1.toString(), data2.toString()); - assertEquals(data1.toString(), data5.toString()); - } - - @Test - public void testEquals() { - assertTrue(data1.equals(data1)); - assertTrue(data1.equals(data2)); - assertFalse(data1.equals(data3)); - assertFalse(data1.equals(data4)); - assertTrue(data1.equals(data5)); - assertFalse(data1.equals(null)); - } - - @Test - public void testHashCode() { - assertEquals(data1.hashCode(), data1.hashCode()); - assertEquals(data3.hashCode(), data3.hashCode()); - assertEquals(data4.hashCode(), data4.hashCode()); - assertEquals(data1.hashCode(), data2.hashCode()); - assertEquals(data1.hashCode(), data5.hashCode()); - assertNotEquals(data1.hashCode(), data3.hashCode()); - assertNotEquals(data1.hashCode(), data4.hashCode()); - assertNotEquals(data3.hashCode(), data4.hashCode()); - } -} \ No newline at end of file + private CompressedBinaryData data1; + private CompressedBinaryData data2; + + private CompressedBinaryData data3; + private CompressedBinaryData data4; + private CompressedBinaryData data5; + + @Before + public void setUp() { + data1 = new CompressedBinaryData("some_data", CompressionType.UNCOMPRESSED); + data2 = new CompressedBinaryData("some_data", CompressionType.UNCOMPRESSED); + + data3 = new CompressedBinaryData("some_other_data", CompressionType.UNCOMPRESSED); + data4 = new CompressedBinaryData("some_data", CompressionType.GZIP); + data5 = data1; + } + + @Test + public void testToString() { + assertEquals(data1.toString(), data1.toString()); + assertEquals(data1.toString(), data2.toString()); + assertEquals(data1.toString(), data5.toString()); + } + + @Test + public void testEquals() { + assertTrue(data1.equals(data1)); + assertTrue(data1.equals(data2)); + assertFalse(data1.equals(data3)); + assertFalse(data1.equals(data4)); + assertTrue(data1.equals(data5)); + assertFalse(data1.equals(null)); + } + + @Test + public void testHashCode() { + assertEquals(data1.hashCode(), data1.hashCode()); + assertEquals(data3.hashCode(), data3.hashCode()); + assertEquals(data4.hashCode(), data4.hashCode()); + assertEquals(data1.hashCode(), data2.hashCode()); + assertEquals(data1.hashCode(), data5.hashCode()); + assertNotEquals(data1.hashCode(), data3.hashCode()); + assertNotEquals(data1.hashCode(), data4.hashCode()); + assertNotEquals(data3.hashCode(), data4.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/DocumentBuilderTest.java b/src/test/java/com/coveo/pushapiclient/DocumentBuilderTest.java index 43f3cf61..33f42ab5 100644 --- a/src/test/java/com/coveo/pushapiclient/DocumentBuilderTest.java +++ b/src/test/java/com/coveo/pushapiclient/DocumentBuilderTest.java @@ -1,378 +1,369 @@ package com.coveo.pushapiclient; -import org.joda.time.DateTime; -import org.joda.time.format.ISODateTimeFormat; -import org.junit.Before; -import org.junit.Test; +import static org.junit.Assert.*; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Date; import java.util.HashMap; - -import static org.junit.Assert.*; +import org.joda.time.DateTime; +import org.joda.time.format.ISODateTimeFormat; +import org.junit.Before; +import org.junit.Test; public class DocumentBuilderTest { - private DocumentBuilder docBuilder; - - @Before - public void setUp() { - docBuilder = new DocumentBuilder("the_uri", "the_title"); - } - - @Test - public void testWithData() { - docBuilder.withData("this is searchable"); - assertEquals( - "withData should marshal correctly", - "this is searchable", - docBuilder.marshalJsonObject().get("data").getAsString() - ); - } - - @Test - public void testWithDatePlainDateObject() { - Date d = new Date(); - DateTime dt = new DateTime(d); - docBuilder.withDate(d); - assertEquals( - "withDate with a plain java date object should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("date").getAsString() - ); - } - - @Test - public void testWithDateLong() { - docBuilder.withDate(12345l); - DateTime dt = new DateTime(12345l); - assertEquals( - "withDate with a long should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("date").getAsString() - ); - } - - @Test - public void testWithDateJodatime() { - DateTime dt = new DateTime(); - docBuilder.withDate(dt); - assertEquals( - "withDate with jodatime should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("date").getAsString() - ); - } - - @Test - public void testWithDateString() { - DateTime dt = new DateTime("2015-01-01"); - docBuilder.withDate("2015-01-01"); - assertEquals( - "withDate with string date should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("date").getAsString() - ); - } - - @Test - public void withModifiedDatePlainDateObject() { - Date d = new Date(); - DateTime dt = new DateTime(d); - docBuilder.withModifiedDate(d); - assertEquals( - "withModifiedDate with a plain java date object should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("modifiedDate").getAsString() - ); - } - - @Test - public void testWithModifiedDateLong() { - docBuilder.withModifiedDate(12345l); - DateTime dt = new DateTime(12345l); - assertEquals( - "withDate with a long should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("modifiedDate").getAsString() - ); - } - - @Test - public void testWithModifiedDateJodatime() { - DateTime dt = new DateTime(); - docBuilder.withModifiedDate(dt); - assertEquals( - "withDate with jodatime should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("modifiedDate").getAsString() - ); - } - - public void testWithModifiedDateString() { - DateTime dt = new DateTime("2015-01-01"); - docBuilder.withModifiedDate("2015-01-01"); - assertEquals( - "withDate with string date should marshal correctly", - dt.toString(ISODateTimeFormat.dateTime()), - docBuilder.marshalJsonObject().get("modifiedDate").getAsString() - ); - } - - @Test - public void testWithPermanentId() { - docBuilder.withPermanentId("the_permanent_id"); - assertEquals( - "with permanentId should marshal correctly", - "the_permanent_id", - docBuilder.marshalJsonObject().get("permanentId").getAsString() - ); - } - - @Test - public void testWithPermanentIdGeneration() { - docBuilder = new DocumentBuilder("https://foo.com", "bar"); - assertEquals( - "permanentId should be generated automatically if not set", - "aa2e0510b66edff7f05e2b30d4f1b3a4b5481c06b69f41751c54675c5afb", - docBuilder.marshalJsonObject().get("permanentId").getAsString() - ); - } - - @Test - public void testWithCompressedBinaryData() { - String encoded = Base64.getEncoder().encodeToString("binary data encoded".getBytes(StandardCharsets.UTF_8)); - docBuilder.withCompressedBinaryData(new CompressedBinaryData(encoded, CompressionType.UNCOMPRESSED)); - String decoded = new String(Base64.getDecoder().decode(docBuilder.marshalJsonObject().get("compressedBinaryData").getAsString().getBytes(StandardCharsets.UTF_8))); - - assertEquals("withCompressedBinaryData should marshal correctly", "binary data encoded", decoded); - } - - @Test - public void testWithFileExtension() { - docBuilder.withFileExtension(".txt"); - - assertEquals( - "withFileExtension should marshal correctly", - ".txt", - docBuilder.marshalJsonObject().get("fileExtension").getAsString() - ); - } - - @Test(expected = RuntimeException.class) - public void testWithInvalidFileExtension() { - docBuilder.withFileExtension("this should blow up"); - } - - @Test - public void testWithParentID() { - docBuilder.withParentID("the_parent_id"); - - assertEquals( - "withParentId should marshal correctly", - "the_parent_id", - docBuilder.marshalJsonObject().get("parentId").getAsString() - ); - } - - @Test - public void testWithClickableUri() { - docBuilder.withClickableUri("the click uri"); - - assertEquals("withClickableUri should marshal correctly", - "the click uri", - docBuilder.marshalJsonObject().get("clickableUri").getAsString() - ); - } - - @Test - public void testWithAuthor() { - docBuilder.withAuthor("the author"); - - assertEquals("withAuthor should marshal correctly", - "the author", - docBuilder.marshalJsonObject().get("author").getAsString() - ); - } - - @Test - public void testWithMetadataValue() { - docBuilder.withMetadataValue("the_key", "the_value"); - assertEquals( - "withMetadataValue should marshal correctly", - "the_value", - docBuilder.marshalJsonObject().get("the_key").getAsString() - ); - assertNull( - "withMetadataValue should remove metadata key when marshaling", - docBuilder.marshalJsonObject().get("metadata") - ); - } - - @Test(expected = RuntimeException.class) - public void testWithInvalidMetadataValue() { - docBuilder.withMetadataValue("data", "this should blow up"); - } - - @Test - public void testWithMetadata() { - docBuilder.withMetadata(new HashMap<>() {{ + private DocumentBuilder docBuilder; + + @Before + public void setUp() { + docBuilder = new DocumentBuilder("the_uri", "the_title"); + } + + @Test + public void testWithData() { + docBuilder.withData("this is searchable"); + assertEquals( + "withData should marshal correctly", + "this is searchable", + docBuilder.marshalJsonObject().get("data").getAsString()); + } + + @Test + public void testWithDatePlainDateObject() { + Date d = new Date(); + DateTime dt = new DateTime(d); + docBuilder.withDate(d); + assertEquals( + "withDate with a plain java date object should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("date").getAsString()); + } + + @Test + public void testWithDateLong() { + docBuilder.withDate(12345l); + DateTime dt = new DateTime(12345l); + assertEquals( + "withDate with a long should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("date").getAsString()); + } + + @Test + public void testWithDateJodatime() { + DateTime dt = new DateTime(); + docBuilder.withDate(dt); + assertEquals( + "withDate with jodatime should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("date").getAsString()); + } + + @Test + public void testWithDateString() { + DateTime dt = new DateTime("2015-01-01"); + docBuilder.withDate("2015-01-01"); + assertEquals( + "withDate with string date should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("date").getAsString()); + } + + @Test + public void withModifiedDatePlainDateObject() { + Date d = new Date(); + DateTime dt = new DateTime(d); + docBuilder.withModifiedDate(d); + assertEquals( + "withModifiedDate with a plain java date object should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("modifiedDate").getAsString()); + } + + @Test + public void testWithModifiedDateLong() { + docBuilder.withModifiedDate(12345l); + DateTime dt = new DateTime(12345l); + assertEquals( + "withDate with a long should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("modifiedDate").getAsString()); + } + + @Test + public void testWithModifiedDateJodatime() { + DateTime dt = new DateTime(); + docBuilder.withModifiedDate(dt); + assertEquals( + "withDate with jodatime should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("modifiedDate").getAsString()); + } + + public void testWithModifiedDateString() { + DateTime dt = new DateTime("2015-01-01"); + docBuilder.withModifiedDate("2015-01-01"); + assertEquals( + "withDate with string date should marshal correctly", + dt.toString(ISODateTimeFormat.dateTime()), + docBuilder.marshalJsonObject().get("modifiedDate").getAsString()); + } + + @Test + public void testWithPermanentId() { + docBuilder.withPermanentId("the_permanent_id"); + assertEquals( + "with permanentId should marshal correctly", + "the_permanent_id", + docBuilder.marshalJsonObject().get("permanentId").getAsString()); + } + + @Test + public void testWithPermanentIdGeneration() { + docBuilder = new DocumentBuilder("https://foo.com", "bar"); + assertEquals( + "permanentId should be generated automatically if not set", + "aa2e0510b66edff7f05e2b30d4f1b3a4b5481c06b69f41751c54675c5afb", + docBuilder.marshalJsonObject().get("permanentId").getAsString()); + } + + @Test + public void testWithCompressedBinaryData() { + String encoded = + Base64.getEncoder().encodeToString("binary data encoded".getBytes(StandardCharsets.UTF_8)); + docBuilder.withCompressedBinaryData( + new CompressedBinaryData(encoded, CompressionType.UNCOMPRESSED)); + String decoded = + new String( + Base64.getDecoder() + .decode( + docBuilder + .marshalJsonObject() + .get("compressedBinaryData") + .getAsString() + .getBytes(StandardCharsets.UTF_8))); + + assertEquals( + "withCompressedBinaryData should marshal correctly", "binary data encoded", decoded); + } + + @Test + public void testWithFileExtension() { + docBuilder.withFileExtension(".txt"); + + assertEquals( + "withFileExtension should marshal correctly", + ".txt", + docBuilder.marshalJsonObject().get("fileExtension").getAsString()); + } + + @Test(expected = RuntimeException.class) + public void testWithInvalidFileExtension() { + docBuilder.withFileExtension("this should blow up"); + } + + @Test + public void testWithParentID() { + docBuilder.withParentID("the_parent_id"); + + assertEquals( + "withParentId should marshal correctly", + "the_parent_id", + docBuilder.marshalJsonObject().get("parentId").getAsString()); + } + + @Test + public void testWithClickableUri() { + docBuilder.withClickableUri("the click uri"); + + assertEquals( + "withClickableUri should marshal correctly", + "the click uri", + docBuilder.marshalJsonObject().get("clickableUri").getAsString()); + } + + @Test + public void testWithAuthor() { + docBuilder.withAuthor("the author"); + + assertEquals( + "withAuthor should marshal correctly", + "the author", + docBuilder.marshalJsonObject().get("author").getAsString()); + } + + @Test + public void testWithMetadataValue() { + docBuilder.withMetadataValue("the_key", "the_value"); + assertEquals( + "withMetadataValue should marshal correctly", + "the_value", + docBuilder.marshalJsonObject().get("the_key").getAsString()); + assertNull( + "withMetadataValue should remove metadata key when marshaling", + docBuilder.marshalJsonObject().get("metadata")); + } + + @Test(expected = RuntimeException.class) + public void testWithInvalidMetadataValue() { + docBuilder.withMetadataValue("data", "this should blow up"); + } + + @Test + public void testWithMetadata() { + docBuilder.withMetadata( + new HashMap<>() { + { put("my_field_1", "1"); put("my_field_2", false); put("my_field_3", 1234); - put("my_field_4", new String[]{"a", "b", "c"}); - }}); - assertEquals( - "1", - docBuilder.marshalJsonObject().get("my_field_1").getAsString() - ); - assertEquals( - false, - docBuilder.marshalJsonObject().get("my_field_2").getAsBoolean() - ); - assertEquals( - 1234, - docBuilder.marshalJsonObject().get("my_field_3").getAsInt() - ); - assertEquals( - "a", - docBuilder.marshalJsonObject().get("my_field_4").getAsJsonArray().get(0).getAsString() - ); - assertEquals( - "b", - docBuilder.marshalJsonObject().get("my_field_4").getAsJsonArray().get(1).getAsString() - ); - assertEquals( - "c", - docBuilder.marshalJsonObject().get("my_field_4").getAsJsonArray().get(2).getAsString() - ); - - } - - @Test - public void testWithSingleAllowedPermissions() { - docBuilder.withAllowedPermissions(new UserSecurityIdentityBuilder("bob@anonymous.com")); - - assertEquals( - "bob@anonymous.com", - docBuilder.marshalJsonObject() - .get("permissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("allowedPermissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("identity").getAsString() - ); - } - - @Test - public void testWithMultipleAllowedPermissions() { - docBuilder.withAllowedPermissions(new UserSecurityIdentityBuilder(new String[]{"bob@anonymous.com", "john@anonymous.com"})); - - assertEquals( - "bob@anonymous.com", - docBuilder.marshalJsonObject() - .get("permissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("allowedPermissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("identity").getAsString() - ); - assertEquals( - "john@anonymous.com", - docBuilder.marshalJsonObject() - .get("permissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("allowedPermissions") - .getAsJsonArray() - .get(1) - .getAsJsonObject() - .get("identity").getAsString() - ); - } - - @Test - public void testWithSingleDeniedPermissions() { - docBuilder.withDeniedPermissions(new UserSecurityIdentityBuilder("bob@anonymous.com")); - - assertEquals( - "bob@anonymous.com", - docBuilder.marshalJsonObject() - .get("permissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("deniedPermissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("identity").getAsString() - ); - } - - @Test - public void testWithMultipleDeniedPermissions() { - docBuilder.withDeniedPermissions(new UserSecurityIdentityBuilder(new String[]{"bob@anonymous.com", "john@anonymous.com"})); - - assertEquals( - "bob@anonymous.com", - docBuilder.marshalJsonObject() - .get("permissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("deniedPermissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("identity").getAsString() - ); - assertEquals( - "john@anonymous.com", - docBuilder.marshalJsonObject() - .get("permissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("deniedPermissions") - .getAsJsonArray() - .get(1) - .getAsJsonObject() - .get("identity").getAsString() - ); - } - - @Test - public void withAllowAnonymousUsers() { - docBuilder.withAllowAnonymousUsers(false); - assertFalse( - "withAllowAnonymousUser should marshal correctly", - docBuilder.marshalJsonObject() - .get("permissions") - .getAsJsonArray() - .get(0) - .getAsJsonObject() - .get("allowAnonymous") - .getAsBoolean()); - } - - @Test - public void marshal() { - String marshaled = docBuilder.marshal(); - assertTrue( - "marshal should return a valid JSON string", - docBuilder.marshal().contains("the_title") - ); - } - + put("my_field_4", new String[] {"a", "b", "c"}); + } + }); + assertEquals("1", docBuilder.marshalJsonObject().get("my_field_1").getAsString()); + assertEquals(false, docBuilder.marshalJsonObject().get("my_field_2").getAsBoolean()); + assertEquals(1234, docBuilder.marshalJsonObject().get("my_field_3").getAsInt()); + assertEquals( + "a", + docBuilder.marshalJsonObject().get("my_field_4").getAsJsonArray().get(0).getAsString()); + assertEquals( + "b", + docBuilder.marshalJsonObject().get("my_field_4").getAsJsonArray().get(1).getAsString()); + assertEquals( + "c", + docBuilder.marshalJsonObject().get("my_field_4").getAsJsonArray().get(2).getAsString()); + } + + @Test + public void testWithSingleAllowedPermissions() { + docBuilder.withAllowedPermissions(new UserSecurityIdentityBuilder("bob@anonymous.com")); + + assertEquals( + "bob@anonymous.com", + docBuilder + .marshalJsonObject() + .get("permissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("allowedPermissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("identity") + .getAsString()); + } + + @Test + public void testWithMultipleAllowedPermissions() { + docBuilder.withAllowedPermissions( + new UserSecurityIdentityBuilder(new String[] {"bob@anonymous.com", "john@anonymous.com"})); + + assertEquals( + "bob@anonymous.com", + docBuilder + .marshalJsonObject() + .get("permissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("allowedPermissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("identity") + .getAsString()); + assertEquals( + "john@anonymous.com", + docBuilder + .marshalJsonObject() + .get("permissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("allowedPermissions") + .getAsJsonArray() + .get(1) + .getAsJsonObject() + .get("identity") + .getAsString()); + } + + @Test + public void testWithSingleDeniedPermissions() { + docBuilder.withDeniedPermissions(new UserSecurityIdentityBuilder("bob@anonymous.com")); + + assertEquals( + "bob@anonymous.com", + docBuilder + .marshalJsonObject() + .get("permissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("deniedPermissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("identity") + .getAsString()); + } + + @Test + public void testWithMultipleDeniedPermissions() { + docBuilder.withDeniedPermissions( + new UserSecurityIdentityBuilder(new String[] {"bob@anonymous.com", "john@anonymous.com"})); + + assertEquals( + "bob@anonymous.com", + docBuilder + .marshalJsonObject() + .get("permissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("deniedPermissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("identity") + .getAsString()); + assertEquals( + "john@anonymous.com", + docBuilder + .marshalJsonObject() + .get("permissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("deniedPermissions") + .getAsJsonArray() + .get(1) + .getAsJsonObject() + .get("identity") + .getAsString()); + } + + @Test + public void withAllowAnonymousUsers() { + docBuilder.withAllowAnonymousUsers(false); + assertFalse( + "withAllowAnonymousUser should marshal correctly", + docBuilder + .marshalJsonObject() + .get("permissions") + .getAsJsonArray() + .get(0) + .getAsJsonObject() + .get("allowAnonymous") + .getAsBoolean()); + } + + @Test + public void marshal() { + String marshaled = docBuilder.marshal(); + assertTrue( + "marshal should return a valid JSON string", docBuilder.marshal().contains("the_title")); + } } diff --git a/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java b/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java index 97c11087..f488f3a5 100644 --- a/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java +++ b/src/test/java/com/coveo/pushapiclient/DocumentUploadQueueTest.java @@ -9,7 +9,6 @@ import java.io.IOException; import java.util.ArrayList; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -19,182 +18,189 @@ public class DocumentUploadQueueTest { - @Mock - private UploadStrategy uploadStrategy; - - @InjectMocks - private DocumentUploadQueue queue; - - private AutoCloseable closeable; - private DocumentBuilder documentToAdd; - private DeleteDocument documentToDelete; - - private int oneMegaByte = 1 * 1024 * 1024; + @Mock private UploadStrategy uploadStrategy; - private String generateStringFromBytes(int numBytes) { - // Check if the number of bytes is valid - if (numBytes <= 0) { - return ""; - } + @InjectMocks private DocumentUploadQueue queue; - // Create a byte array with the specified length - byte[] bytes = new byte[numBytes]; + private AutoCloseable closeable; + private DocumentBuilder documentToAdd; + private DeleteDocument documentToDelete; - // Fill the byte array with a pattern of ASCII characters - byte pattern = 65; // ASCII value for 'A' - for (int i = 0; i < numBytes; i++) { - bytes[i] = pattern; - } + private int oneMegaByte = 1 * 1024 * 1024; - return new String(bytes); + private String generateStringFromBytes(int numBytes) { + // Check if the number of bytes is valid + if (numBytes <= 0) { + return ""; } - private DocumentBuilder generateDocumentFromSize(int numBytes) { - return new DocumentBuilder("https://my.document.uri?ref=1", - "My bulky document") - .withData(generateStringFromBytes(numBytes)); - } - - @Before - public void setup() { - String twoMegaByteData = generateStringFromBytes(2 * oneMegaByte); - - documentToAdd = new DocumentBuilder( - "https://my.document.uri?ref=1", - "My new document") - .withData(twoMegaByteData); + // Create a byte array with the specified length + byte[] bytes = new byte[numBytes]; - documentToDelete = new DeleteDocument("https://my.document.uri?ref=3"); - - closeable = MockitoAnnotations.openMocks(this); - } - - @After - public void closeService() throws Exception { - closeable.close(); + // Fill the byte array with a pattern of ASCII characters + byte pattern = 65; // ASCII value for 'A' + for (int i = 0; i < numBytes; i++) { + bytes[i] = pattern; } - @Test - public void testIsEmpty() throws IOException, InterruptedException { - assertTrue(queue.isEmpty()); - } - - @Test - public void testIsNotEmpty() throws IOException, InterruptedException { - queue.add(documentToAdd); - assertFalse(queue.isEmpty()); - } - - @Test - public void testShouldReturnBatch() throws IOException, InterruptedException { - BatchUpdate batchUpdate = new BatchUpdate( - new ArrayList<>() { - { - add(documentToAdd); - } - }, new ArrayList<>() { - { - add(documentToDelete); - } - }); - queue.add(documentToAdd); - queue.add(documentToDelete); - - assertEquals(batchUpdate, queue.getBatch()); - } - - @Test - public void testFlushShouldNotUploadDocumentsWhenRequiredSizeIsNotMet() throws IOException, InterruptedException { - // Adding 2MB document to the queue => queue has now 3MB of free space - // (5MB - 2MB = 3MB) - queue.add(documentToAdd); - // Adding 2MB document to the queue => queue has now 1MB of free space - // (3MB - 2MB = 1MB) - queue.add(documentToDelete); - - // The maximum queue size has not been reached yet (1MB left of free space). - // Therefore, the accumulated documents will not be automatically flushed. - // Unless the user runs `.flush()` the queue will keep the 4MB of documents - verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); - } - - @Test - public void testShouldAutomaticallyFlushAccumulatedDocuments() throws IOException, InterruptedException { - DocumentBuilder firstBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); - DocumentBuilder secondBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); - DocumentBuilder thirdBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); - ArrayList emptyList = new ArrayList<>(); - BatchUpdate firstBatch = new BatchUpdate( - new ArrayList<>() { - { - add(firstBulkyDocument); - add(secondBulkyDocument); - } - }, emptyList); - - // Adding 3 documents of 2MB to the queue. After adding the first 2 documents, - // the queue size will reach 6MB, which exceeds the maximum queue size - // limit by 1MB. Therefore, the 2 first added documents will automatically be - // uploaded to the source. - queue.add(firstBulkyDocument); - queue.add(secondBulkyDocument); - verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); - - // The 3rd document added to the queue will be included in a separate batch, - // which will not be uploaded unless the `flush()` method is called or until the - // queue size limit has been reached - queue.add(thirdBulkyDocument); - - verify(uploadStrategy, times(1)).apply(any(BatchUpdate.class)); - verify(uploadStrategy, times(1)).apply(firstBatch); - } - - @Test - public void testShouldManuallyFlushAccumulatedDocuments() throws IOException, InterruptedException { - DocumentBuilder firstBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); - DocumentBuilder secondBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); - DocumentBuilder thirdBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); - ArrayList emptyList = new ArrayList<>(); - BatchUpdate firstBatch = new BatchUpdate( - new ArrayList<>() { - { - add(firstBulkyDocument); - add(secondBulkyDocument); - } - }, emptyList); - - BatchUpdate secondBatch = new BatchUpdate( - new ArrayList<>() { - { - add(thirdBulkyDocument); - } - }, emptyList); - - // Adding 3 documents of 2MB to the queue. After adding the first 2 documents, - // the queue size will reach 6MB, which exceeds the maximum queue size - // limit. Therefore, the 2 first added documents will automatically be uploaded - // to the source. - queue.add(firstBulkyDocument); - queue.add(secondBulkyDocument); - queue.add(thirdBulkyDocument); - - queue.flush(); - - // Additional flush will have no effect if documents where already flushed - queue.flush(); - - verify(uploadStrategy, times(2)).apply(any(BatchUpdate.class)); - verify(uploadStrategy, times(1)).apply(firstBatch); - verify(uploadStrategy, times(1)).apply(secondBatch); - } - - @Test - public void testAddingEmptyDocument() throws IOException, InterruptedException { - DocumentBuilder nullDocument = null; - - queue.add(nullDocument); - queue.flush(); - - verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); - } + return new String(bytes); + } + + private DocumentBuilder generateDocumentFromSize(int numBytes) { + return new DocumentBuilder("https://my.document.uri?ref=1", "My bulky document") + .withData(generateStringFromBytes(numBytes)); + } + + @Before + public void setup() { + String twoMegaByteData = generateStringFromBytes(2 * oneMegaByte); + + documentToAdd = + new DocumentBuilder("https://my.document.uri?ref=1", "My new document") + .withData(twoMegaByteData); + + documentToDelete = new DeleteDocument("https://my.document.uri?ref=3"); + + closeable = MockitoAnnotations.openMocks(this); + } + + @After + public void closeService() throws Exception { + closeable.close(); + } + + @Test + public void testIsEmpty() throws IOException, InterruptedException { + assertTrue(queue.isEmpty()); + } + + @Test + public void testIsNotEmpty() throws IOException, InterruptedException { + queue.add(documentToAdd); + assertFalse(queue.isEmpty()); + } + + @Test + public void testShouldReturnBatch() throws IOException, InterruptedException { + BatchUpdate batchUpdate = + new BatchUpdate( + new ArrayList<>() { + { + add(documentToAdd); + } + }, + new ArrayList<>() { + { + add(documentToDelete); + } + }); + queue.add(documentToAdd); + queue.add(documentToDelete); + + assertEquals(batchUpdate, queue.getBatch()); + } + + @Test + public void testFlushShouldNotUploadDocumentsWhenRequiredSizeIsNotMet() + throws IOException, InterruptedException { + // Adding 2MB document to the queue => queue has now 3MB of free space + // (5MB - 2MB = 3MB) + queue.add(documentToAdd); + // Adding 2MB document to the queue => queue has now 1MB of free space + // (3MB - 2MB = 1MB) + queue.add(documentToDelete); + + // The maximum queue size has not been reached yet (1MB left of free space). + // Therefore, the accumulated documents will not be automatically flushed. + // Unless the user runs `.flush()` the queue will keep the 4MB of documents + verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); + } + + @Test + public void testShouldAutomaticallyFlushAccumulatedDocuments() + throws IOException, InterruptedException { + DocumentBuilder firstBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder secondBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder thirdBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + ArrayList emptyList = new ArrayList<>(); + BatchUpdate firstBatch = + new BatchUpdate( + new ArrayList<>() { + { + add(firstBulkyDocument); + add(secondBulkyDocument); + } + }, + emptyList); + + // Adding 3 documents of 2MB to the queue. After adding the first 2 documents, + // the queue size will reach 6MB, which exceeds the maximum queue size + // limit by 1MB. Therefore, the 2 first added documents will automatically be + // uploaded to the source. + queue.add(firstBulkyDocument); + queue.add(secondBulkyDocument); + verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); + + // The 3rd document added to the queue will be included in a separate batch, + // which will not be uploaded unless the `flush()` method is called or until the + // queue size limit has been reached + queue.add(thirdBulkyDocument); + + verify(uploadStrategy, times(1)).apply(any(BatchUpdate.class)); + verify(uploadStrategy, times(1)).apply(firstBatch); + } + + @Test + public void testShouldManuallyFlushAccumulatedDocuments() + throws IOException, InterruptedException { + DocumentBuilder firstBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder secondBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + DocumentBuilder thirdBulkyDocument = generateDocumentFromSize(2 * oneMegaByte); + ArrayList emptyList = new ArrayList<>(); + BatchUpdate firstBatch = + new BatchUpdate( + new ArrayList<>() { + { + add(firstBulkyDocument); + add(secondBulkyDocument); + } + }, + emptyList); + + BatchUpdate secondBatch = + new BatchUpdate( + new ArrayList<>() { + { + add(thirdBulkyDocument); + } + }, + emptyList); + + // Adding 3 documents of 2MB to the queue. After adding the first 2 documents, + // the queue size will reach 6MB, which exceeds the maximum queue size + // limit. Therefore, the 2 first added documents will automatically be uploaded + // to the source. + queue.add(firstBulkyDocument); + queue.add(secondBulkyDocument); + queue.add(thirdBulkyDocument); + + queue.flush(); + + // Additional flush will have no effect if documents where already flushed + queue.flush(); + + verify(uploadStrategy, times(2)).apply(any(BatchUpdate.class)); + verify(uploadStrategy, times(1)).apply(firstBatch); + verify(uploadStrategy, times(1)).apply(secondBatch); + } + + @Test + public void testAddingEmptyDocument() throws IOException, InterruptedException { + DocumentBuilder nullDocument = null; + + queue.add(nullDocument); + queue.flush(); + + verify(uploadStrategy, times(0)).apply(any(BatchUpdate.class)); + } } diff --git a/src/test/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilderTest.java b/src/test/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilderTest.java index bb14e718..733cc506 100644 --- a/src/test/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilderTest.java +++ b/src/test/java/com/coveo/pushapiclient/GroupSecurityIdentityBuilderTest.java @@ -1,76 +1,79 @@ package com.coveo.pushapiclient; -import org.junit.Before; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; -public class GroupSecurityIdentityBuilderTest { +import org.junit.Before; +import org.junit.Test; - private GroupSecurityIdentityBuilder gsib1; - private GroupSecurityIdentityBuilder gsib2; - private GroupSecurityIdentityBuilder gsib3; - private GroupSecurityIdentityBuilder gsib4; - private GroupSecurityIdentityBuilder gsib5; +public class GroupSecurityIdentityBuilderTest { - @Before - public void setUp() { - String[] id1 = new String[]{"identity1", "identity2"}; - String[] id2 = new String[]{"identity2", "identity3"}; + private GroupSecurityIdentityBuilder gsib1; + private GroupSecurityIdentityBuilder gsib2; + private GroupSecurityIdentityBuilder gsib3; + private GroupSecurityIdentityBuilder gsib4; + private GroupSecurityIdentityBuilder gsib5; - gsib1 = new GroupSecurityIdentityBuilder(id1, "some_sec_provider"); - gsib2 = new GroupSecurityIdentityBuilder(id1, "some_sec_provider"); - gsib3 = new GroupSecurityIdentityBuilder(id2, "some_sec_provider"); - gsib4 = new GroupSecurityIdentityBuilder(id1, "some_other_sec_provider"); - gsib5 = gsib1; - } + @Before + public void setUp() { + String[] id1 = new String[] {"identity1", "identity2"}; + String[] id2 = new String[] {"identity2", "identity3"}; - @Test - public void testSingleIdentities() { - SecurityIdentity identityBuilt = new GroupSecurityIdentityBuilder("bob@foo.com", "my provider").build()[0]; - assertEquals("bob@foo.com", identityBuilt.identity); - assertEquals(SecurityIdentityType.GROUP, identityBuilt.identityType); - assertEquals("my provider", identityBuilt.securityProvider); - } + gsib1 = new GroupSecurityIdentityBuilder(id1, "some_sec_provider"); + gsib2 = new GroupSecurityIdentityBuilder(id1, "some_sec_provider"); + gsib3 = new GroupSecurityIdentityBuilder(id2, "some_sec_provider"); + gsib4 = new GroupSecurityIdentityBuilder(id1, "some_other_sec_provider"); + gsib5 = gsib1; + } - @Test - public void testMultipleIdentities() { - SecurityIdentity[] identitiesBuilt = new GroupSecurityIdentityBuilder(new String[]{"bob@foo.com", "john@foo.com"}, "my provider").build(); + @Test + public void testSingleIdentities() { + SecurityIdentity identityBuilt = + new GroupSecurityIdentityBuilder("bob@foo.com", "my provider").build()[0]; + assertEquals("bob@foo.com", identityBuilt.identity); + assertEquals(SecurityIdentityType.GROUP, identityBuilt.identityType); + assertEquals("my provider", identityBuilt.securityProvider); + } - assertEquals("bob@foo.com", identitiesBuilt[0].identity); - assertEquals("john@foo.com", identitiesBuilt[1].identity); + @Test + public void testMultipleIdentities() { + SecurityIdentity[] identitiesBuilt = + new GroupSecurityIdentityBuilder( + new String[] {"bob@foo.com", "john@foo.com"}, "my provider") + .build(); - } + assertEquals("bob@foo.com", identitiesBuilt[0].identity); + assertEquals("john@foo.com", identitiesBuilt[1].identity); + } - @Test - public void testToString() { - assertEquals(gsib1.toString(), gsib1.toString()); - assertEquals(gsib1.toString(), gsib2.toString()); - assertEquals(gsib1.toString(), gsib5.toString()); - assertNotEquals(gsib1.toString(), gsib3.toString()); - assertNotEquals(gsib3.toString(), gsib4.toString()); - } + @Test + public void testToString() { + assertEquals(gsib1.toString(), gsib1.toString()); + assertEquals(gsib1.toString(), gsib2.toString()); + assertEquals(gsib1.toString(), gsib5.toString()); + assertNotEquals(gsib1.toString(), gsib3.toString()); + assertNotEquals(gsib3.toString(), gsib4.toString()); + } - @Test - public void testEquals() { - assertTrue(gsib1.equals(gsib1)); - assertTrue(gsib1.equals(gsib2)); - assertTrue(gsib1.equals(gsib5)); - assertFalse(gsib3.equals(gsib1)); - assertFalse(gsib3.equals(gsib4)); - assertFalse(gsib1.equals(null)); - } + @Test + public void testEquals() { + assertTrue(gsib1.equals(gsib1)); + assertTrue(gsib1.equals(gsib2)); + assertTrue(gsib1.equals(gsib5)); + assertFalse(gsib3.equals(gsib1)); + assertFalse(gsib3.equals(gsib4)); + assertFalse(gsib1.equals(null)); + } - @Test - public void testHashCode() { - assertEquals(gsib1.hashCode(), gsib1.hashCode()); - assertEquals(gsib1.hashCode(), gsib2.hashCode()); - assertEquals(gsib1.hashCode(), gsib5.hashCode()); - assertEquals(gsib3.hashCode(), gsib3.hashCode()); - assertNotEquals(gsib1.hashCode(), gsib3.hashCode()); - assertNotEquals(gsib3.hashCode(), gsib4.hashCode()); - } -} \ No newline at end of file + @Test + public void testHashCode() { + assertEquals(gsib1.hashCode(), gsib1.hashCode()); + assertEquals(gsib1.hashCode(), gsib2.hashCode()); + assertEquals(gsib1.hashCode(), gsib5.hashCode()); + assertEquals(gsib3.hashCode(), gsib3.hashCode()); + assertNotEquals(gsib1.hashCode(), gsib3.hashCode()); + assertNotEquals(gsib3.hashCode(), gsib4.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java b/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java index 20eda8af..b411d46f 100644 --- a/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java +++ b/src/test/java/com/coveo/pushapiclient/PlatformClientTest.java @@ -1,10 +1,12 @@ package com.coveo.pushapiclient; -import com.google.gson.Gson; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import com.google.gson.Gson; import java.io.IOException; import java.net.http.HttpClient; import java.net.http.HttpRequest; @@ -12,321 +14,443 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; public class PlatformClientTest { - private PlatformClient client; - private HttpClient httpClient; - private ArgumentCaptor argument; - - public void assertAuthorizationHeader() { - assertTrue(this.argument.getValue().headers().map().get("Authorization").contains("Bearer the_api_key")); - } - - public void assertApplicationJsonHeader() { - assertTrue(this.argument.getValue().headers().map().get("Content-Type").contains("application/json")); - assertTrue(this.argument.getValue().headers().map().get("Accept").contains("application/json")); - } - - public SecurityIdentityModel securityIdentityModel() { - return new SecurityIdentityModel(identityModels(), identityModel(), identityModels()); - } - - public SecurityIdentityAliasModel securityIdentityAliasModel() { - return new SecurityIdentityAliasModel(aliasMappings(), identityModel(), identityModels()); - } - - public SecurityIdentityDelete securityIdentityDelete() { - return new SecurityIdentityDelete(identityModel()); - } - - public SecurityIdentityBatchConfig securityIdentityBatchConfig() { - return new SecurityIdentityBatchConfig("the_file_id", 1234L); - } - - public DocumentBuilder documentBuilder() { - return new DocumentBuilder("the_uri", "the_title"); - } - - public DeleteDocument deleteDocument() { - return new DeleteDocument("12345"); - } - - public Document document() { - return documentBuilder().getDocument(); - } - - public String documentString() { - return documentBuilder().marshal(); - } - - public FileContainer fileContainer() { - FileContainer fileContainer = new FileContainer(); - fileContainer.fileId = "the_file_id"; - fileContainer.requiredHeaders = new HashMap<>() {{ - put("foo", "bar"); - }}; - fileContainer.uploadUri = "https://upload.uri"; - return fileContainer; - } - - public BatchUpdateRecord batchUpdateRecord() { - BatchUpdate batchUpdate = new BatchUpdate(new ArrayList<>() {{ - add(documentBuilder()); - }}, new ArrayList<>() {{ - add(deleteDocument()); - }}); - return batchUpdate.marshal(); - } - - public IdentityModel identityModel() { - return new IdentityModel("the_name_identity_model", SecurityIdentityType.USER, new HashMap<>() {{ + private PlatformClient client; + private HttpClient httpClient; + private ArgumentCaptor argument; + + public void assertAuthorizationHeader() { + assertTrue( + this.argument + .getValue() + .headers() + .map() + .get("Authorization") + .contains("Bearer the_api_key")); + } + + public void assertApplicationJsonHeader() { + assertTrue( + this.argument.getValue().headers().map().get("Content-Type").contains("application/json")); + assertTrue(this.argument.getValue().headers().map().get("Accept").contains("application/json")); + } + + public SecurityIdentityModel securityIdentityModel() { + return new SecurityIdentityModel(identityModels(), identityModel(), identityModels()); + } + + public SecurityIdentityAliasModel securityIdentityAliasModel() { + return new SecurityIdentityAliasModel(aliasMappings(), identityModel(), identityModels()); + } + + public SecurityIdentityDelete securityIdentityDelete() { + return new SecurityIdentityDelete(identityModel()); + } + + public SecurityIdentityBatchConfig securityIdentityBatchConfig() { + return new SecurityIdentityBatchConfig("the_file_id", 1234L); + } + + public DocumentBuilder documentBuilder() { + return new DocumentBuilder("the_uri", "the_title"); + } + + public DeleteDocument deleteDocument() { + return new DeleteDocument("12345"); + } + + public Document document() { + return documentBuilder().getDocument(); + } + + public String documentString() { + return documentBuilder().marshal(); + } + + public FileContainer fileContainer() { + FileContainer fileContainer = new FileContainer(); + fileContainer.fileId = "the_file_id"; + fileContainer.requiredHeaders = + new HashMap<>() { + { put("foo", "bar"); - }}); - } - - public IdentityModel[] identityModels() { - return new IdentityModel[]{identityModel()}; - } - - public AliasMapping[] aliasMappings() { - return new AliasMapping[]{new AliasMapping("the_provider_alias", "the_name_alias", SecurityIdentityType.USER, new HashMap<>() {{ + } + }; + fileContainer.uploadUri = "https://upload.uri"; + return fileContainer; + } + + public BatchUpdateRecord batchUpdateRecord() { + BatchUpdate batchUpdate = + new BatchUpdate( + new ArrayList<>() { + { + add(documentBuilder()); + } + }, + new ArrayList<>() { + { + add(deleteDocument()); + } + }); + return batchUpdate.marshal(); + } + + public IdentityModel identityModel() { + return new IdentityModel( + "the_name_identity_model", + SecurityIdentityType.USER, + new HashMap<>() { + { put("foo", "bar"); - }})}; - } - - @Before - public void setupClient() { - this.httpClient = mock(HttpClient.class); - this.client = new PlatformClient("the_api_key", "the_org_id", this.httpClient); - this.argument = ArgumentCaptor.forClass(HttpRequest.class); - } - - @Test - public void testCreatePushSource() throws IOException, InterruptedException { - client.createSource("the_name", SourceType.PUSH, SourceVisibility.SECURED); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("POST", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources")); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - - Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); - assertEquals("the_name", requestBody.get("name")); - assertEquals(SourceVisibility.SECURED.toString(), requestBody.get("sourceVisibility")); - assertEquals("PUSH", requestBody.get("sourceType")); - assertEquals(true, requestBody.get("pushEnabled")); - } - - @Test - public void testCreateCatalogSource() throws IOException, InterruptedException { - client.createSource("the_name", SourceType.CATALOG, SourceVisibility.SECURED); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("POST", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources")); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - - Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); - assertEquals("the_name", requestBody.get("name")); - assertEquals(SourceVisibility.SECURED.toString(), requestBody.get("sourceVisibility")); - assertEquals("CATALOG", requestBody.get("sourceType")); - assertEquals(true, requestBody.get("pushEnabled")); - assertEquals(true, requestBody.get("streamEnabled")); - } - - @Test - public void testCreateOrUpdateSecurityIdentity() throws IOException, InterruptedException { - client.createOrUpdateSecurityIdentity("my_provider", securityIdentityModel()); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("PUT", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/providers/my_provider/permissions")); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - - Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); - - ArrayList members = (ArrayList) requestBody.get("members"); - ArrayList wellKnowns = (ArrayList) requestBody.get("wellKnowns"); - Map identity = (Map) requestBody.get("identity"); - - assertEquals(identityModel().name, members.get(0).get("name")); - assertEquals(identityModel().additionalInfo.get("foo"), ((Map) members.get(0).get("additionalInfo")).get("foo")); - assertEquals(identityModel().name, wellKnowns.get(0).get("name")); - assertEquals(identityModel().additionalInfo.get("foo"), ((Map) wellKnowns.get(0).get("additionalInfo")).get("foo")); - assertEquals(identityModel().name, identity.get("name")); - assertEquals(identityModel().additionalInfo.get("foo"), ((Map) identity.get("additionalInfo")).get("foo")); - } - - @Test - public void testCreateOrUpdateSecurityIdentityAlias() throws IOException, InterruptedException { - client.createOrUpdateSecurityIdentityAlias("my_provider", securityIdentityAliasModel()); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("PUT", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/providers/my_provider/mappings")); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - - Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); - - ArrayList mappings = (ArrayList) requestBody.get("mappings"); - ArrayList wellKnowns = (ArrayList) requestBody.get("wellKnowns"); - Map identity = (Map) requestBody.get("identity"); - - assertEquals(aliasMappings()[0].name, mappings.get(0).get("name")); - assertEquals(aliasMappings()[0].additionalInfo.get("foo"), ((Map) mappings.get(0).get("additionalInfo")).get("foo")); - assertEquals(identityModel().name, wellKnowns.get(0).get("name")); - assertEquals(identityModel().additionalInfo.get("foo"), ((Map) wellKnowns.get(0).get("additionalInfo")).get("foo")); - assertEquals(identityModel().name, identity.get("name")); - assertEquals(identityModel().additionalInfo.get("foo"), ((Map) identity.get("additionalInfo")).get("foo")); - } - - @Test - public void testDeleteSecurityIdentity() throws IOException, InterruptedException { - client.deleteSecurityIdentity("my_provider", securityIdentityDelete()); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("DELETE", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/providers/my_provider/permissions")); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - - Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); - Map identity = (Map) requestBody.get("identity"); - - assertEquals(identityModel().name, identity.get("name")); - } - - @Test - public void testManageSecurityIdentities() throws IOException, InterruptedException { - client.manageSecurityIdentities("my_provider", securityIdentityBatchConfig()); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("PUT", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/providers/my_provider/permissions/batch")); - assertTrue(argument.getValue().uri().getQuery().contains(String.format("fileId=%s", securityIdentityBatchConfig().getFileId()))); - assertTrue(argument.getValue().uri().getQuery().contains(String.format("orderingId=%s", securityIdentityBatchConfig().getOrderingId()))); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - } - - @Test - public void testAppendOrderingId() throws IOException, InterruptedException { - String standardOrderingParam = client.appendOrderingId(1234L); - String noOrderingParam = client.appendOrderingId(0L); - - assertTrue(standardOrderingParam.contains(String.format("orderingId=%s", "1234"))); - assertEquals("", noOrderingParam); - } - - @Test - public void testPushDocument() throws IOException, InterruptedException { - client.pushDocument("my_source", documentString(), document().uri, CompressionType.UNCOMPRESSED); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("PUT", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/documents")); - assertTrue(argument.getValue().uri().getQuery().contains(String.format("documentId=%s", document().uri))); - assertTrue(argument.getValue().uri().getQuery().contains(String.format("compressionType=%s", CompressionType.UNCOMPRESSED.toString()))); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - - Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); - assertEquals(document().title, requestBody.get("title")); - } - - @Test - public void testCreateFileContainer() throws IOException, InterruptedException { - client.createFileContainer(); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("POST", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/files")); - assertAuthorizationHeader(); - assertApplicationJsonHeader(); - } - - @Test - public void testUploadContentToFileContainer() throws IOException, InterruptedException { - client.uploadContentToFileContainer(fileContainer(), new Gson().toJson(batchUpdateRecord())); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("PUT", argument.getValue().method()); - assertTrue(argument.getValue().uri().toString().equals(fileContainer().uploadUri)); - assertEquals(argument.getValue().headers().map().get("foo").get(0), fileContainer().requiredHeaders.get("foo")); - - Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); - ArrayList addOrUpdate = (ArrayList) requestBody.get("addOrUpdate"); - ArrayList delete = (ArrayList) requestBody.get("delete"); - - assertEquals(document().uri, addOrUpdate.get(0).get("documentId")); - assertEquals(deleteDocument().documentId, delete.get(0).get("documentId")); - } - - @Test - public void testPushFileContainerContent() throws IOException, InterruptedException { - client.pushFileContainerContent("my_source", fileContainer()); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("PUT", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/documents/batch")); - assertTrue(argument.getValue().uri().getQuery().contains(String.format("fileId=%s", fileContainer().fileId))); - assertApplicationJsonHeader(); - assertAuthorizationHeader(); - } - - @Test - public void testOpenStream() throws IOException, InterruptedException { - client.openStream("my_source"); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("POST", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/stream/open")); - assertApplicationJsonHeader(); - assertAuthorizationHeader(); - } - - @Test - public void testRequireStreamChunk() throws IOException, InterruptedException { - client.requireStreamChunk("my_source", "stream_id"); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("POST", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/stream/stream_id/chunk")); - assertApplicationJsonHeader(); - assertAuthorizationHeader(); - } - - @Test - public void testCloseStream() throws IOException, InterruptedException { - client.closeStream("my_source", "stream_id"); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("POST", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/stream/stream_id/close")); - assertApplicationJsonHeader(); - assertAuthorizationHeader(); - } - - @Test - public void testDeleteDocument() throws IOException, InterruptedException { - client.deleteDocument("my_source", document().uri, true); - verify(httpClient).send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); - - assertEquals("DELETE", argument.getValue().method()); - assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/documents")); - assertTrue(argument.getValue().uri().getQuery().contains("deleteChildren=true")); - assertTrue(argument.getValue().uri().getQuery().contains(String.format("documentId=%s", document().uri))); - assertApplicationJsonHeader(); - assertAuthorizationHeader(); - } -} \ No newline at end of file + } + }); + } + + public IdentityModel[] identityModels() { + return new IdentityModel[] {identityModel()}; + } + + public AliasMapping[] aliasMappings() { + return new AliasMapping[] { + new AliasMapping( + "the_provider_alias", + "the_name_alias", + SecurityIdentityType.USER, + new HashMap<>() { + { + put("foo", "bar"); + } + }) + }; + } + + @Before + public void setupClient() { + this.httpClient = mock(HttpClient.class); + this.client = new PlatformClient("the_api_key", "the_org_id", this.httpClient); + this.argument = ArgumentCaptor.forClass(HttpRequest.class); + } + + @Test + public void testCreatePushSource() throws IOException, InterruptedException { + client.createSource("the_name", SourceType.PUSH, SourceVisibility.SECURED); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources")); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + assertEquals("the_name", requestBody.get("name")); + assertEquals(SourceVisibility.SECURED.toString(), requestBody.get("sourceVisibility")); + assertEquals("PUSH", requestBody.get("sourceType")); + assertEquals(true, requestBody.get("pushEnabled")); + } + + @Test + public void testCreateCatalogSource() throws IOException, InterruptedException { + client.createSource("the_name", SourceType.CATALOG, SourceVisibility.SECURED); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue(argument.getValue().uri().getPath().contains("the_org_id/sources")); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + assertEquals("the_name", requestBody.get("name")); + assertEquals(SourceVisibility.SECURED.toString(), requestBody.get("sourceVisibility")); + assertEquals("CATALOG", requestBody.get("sourceType")); + assertEquals(true, requestBody.get("pushEnabled")); + assertEquals(true, requestBody.get("streamEnabled")); + } + + @Test + public void testCreateOrUpdateSecurityIdentity() throws IOException, InterruptedException { + client.createOrUpdateSecurityIdentity("my_provider", securityIdentityModel()); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("PUT", argument.getValue().method()); + assertTrue( + argument + .getValue() + .uri() + .getPath() + .contains("the_org_id/providers/my_provider/permissions")); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + + ArrayList members = (ArrayList) requestBody.get("members"); + ArrayList wellKnowns = (ArrayList) requestBody.get("wellKnowns"); + Map identity = (Map) requestBody.get("identity"); + + assertEquals(identityModel().name, members.get(0).get("name")); + assertEquals( + identityModel().additionalInfo.get("foo"), + ((Map) members.get(0).get("additionalInfo")).get("foo")); + assertEquals(identityModel().name, wellKnowns.get(0).get("name")); + assertEquals( + identityModel().additionalInfo.get("foo"), + ((Map) wellKnowns.get(0).get("additionalInfo")).get("foo")); + assertEquals(identityModel().name, identity.get("name")); + assertEquals( + identityModel().additionalInfo.get("foo"), + ((Map) identity.get("additionalInfo")).get("foo")); + } + + @Test + public void testCreateOrUpdateSecurityIdentityAlias() throws IOException, InterruptedException { + client.createOrUpdateSecurityIdentityAlias("my_provider", securityIdentityAliasModel()); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("PUT", argument.getValue().method()); + assertTrue( + argument.getValue().uri().getPath().contains("the_org_id/providers/my_provider/mappings")); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + + ArrayList mappings = (ArrayList) requestBody.get("mappings"); + ArrayList wellKnowns = (ArrayList) requestBody.get("wellKnowns"); + Map identity = (Map) requestBody.get("identity"); + + assertEquals(aliasMappings()[0].name, mappings.get(0).get("name")); + assertEquals( + aliasMappings()[0].additionalInfo.get("foo"), + ((Map) mappings.get(0).get("additionalInfo")).get("foo")); + assertEquals(identityModel().name, wellKnowns.get(0).get("name")); + assertEquals( + identityModel().additionalInfo.get("foo"), + ((Map) wellKnowns.get(0).get("additionalInfo")).get("foo")); + assertEquals(identityModel().name, identity.get("name")); + assertEquals( + identityModel().additionalInfo.get("foo"), + ((Map) identity.get("additionalInfo")).get("foo")); + } + + @Test + public void testDeleteSecurityIdentity() throws IOException, InterruptedException { + client.deleteSecurityIdentity("my_provider", securityIdentityDelete()); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("DELETE", argument.getValue().method()); + assertTrue( + argument + .getValue() + .uri() + .getPath() + .contains("the_org_id/providers/my_provider/permissions")); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + Map identity = (Map) requestBody.get("identity"); + + assertEquals(identityModel().name, identity.get("name")); + } + + @Test + public void testManageSecurityIdentities() throws IOException, InterruptedException { + client.manageSecurityIdentities("my_provider", securityIdentityBatchConfig()); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("PUT", argument.getValue().method()); + assertTrue( + argument + .getValue() + .uri() + .getPath() + .contains("the_org_id/providers/my_provider/permissions/batch")); + assertTrue( + argument + .getValue() + .uri() + .getQuery() + .contains(String.format("fileId=%s", securityIdentityBatchConfig().getFileId()))); + assertTrue( + argument + .getValue() + .uri() + .getQuery() + .contains( + String.format("orderingId=%s", securityIdentityBatchConfig().getOrderingId()))); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + } + + @Test + public void testAppendOrderingId() throws IOException, InterruptedException { + String standardOrderingParam = client.appendOrderingId(1234L); + String noOrderingParam = client.appendOrderingId(0L); + + assertTrue(standardOrderingParam.contains(String.format("orderingId=%s", "1234"))); + assertEquals("", noOrderingParam); + } + + @Test + public void testPushDocument() throws IOException, InterruptedException { + client.pushDocument( + "my_source", documentString(), document().uri, CompressionType.UNCOMPRESSED); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("PUT", argument.getValue().method()); + assertTrue( + argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/documents")); + assertTrue( + argument + .getValue() + .uri() + .getQuery() + .contains(String.format("documentId=%s", document().uri))); + assertTrue( + argument + .getValue() + .uri() + .getQuery() + .contains( + String.format("compressionType=%s", CompressionType.UNCOMPRESSED.toString()))); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + assertEquals(document().title, requestBody.get("title")); + } + + @Test + public void testCreateFileContainer() throws IOException, InterruptedException { + client.createFileContainer(); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue(argument.getValue().uri().getPath().contains("the_org_id/files")); + assertAuthorizationHeader(); + assertApplicationJsonHeader(); + } + + @Test + public void testUploadContentToFileContainer() throws IOException, InterruptedException { + client.uploadContentToFileContainer(fileContainer(), new Gson().toJson(batchUpdateRecord())); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("PUT", argument.getValue().method()); + assertTrue(argument.getValue().uri().toString().equals(fileContainer().uploadUri)); + assertEquals( + argument.getValue().headers().map().get("foo").get(0), + fileContainer().requiredHeaders.get("foo")); + + Map requestBody = StringSubscriber.toMap(argument.getValue().bodyPublisher()); + ArrayList addOrUpdate = (ArrayList) requestBody.get("addOrUpdate"); + ArrayList delete = (ArrayList) requestBody.get("delete"); + + assertEquals(document().uri, addOrUpdate.get(0).get("documentId")); + assertEquals(deleteDocument().documentId, delete.get(0).get("documentId")); + } + + @Test + public void testPushFileContainerContent() throws IOException, InterruptedException { + client.pushFileContainerContent("my_source", fileContainer()); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("PUT", argument.getValue().method()); + assertTrue( + argument + .getValue() + .uri() + .getPath() + .contains("the_org_id/sources/my_source/documents/batch")); + assertTrue( + argument + .getValue() + .uri() + .getQuery() + .contains(String.format("fileId=%s", fileContainer().fileId))); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } + + @Test + public void testOpenStream() throws IOException, InterruptedException { + client.openStream("my_source"); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue( + argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/stream/open")); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } + + @Test + public void testRequireStreamChunk() throws IOException, InterruptedException { + client.requireStreamChunk("my_source", "stream_id"); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue( + argument + .getValue() + .uri() + .getPath() + .contains("the_org_id/sources/my_source/stream/stream_id/chunk")); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } + + @Test + public void testCloseStream() throws IOException, InterruptedException { + client.closeStream("my_source", "stream_id"); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("POST", argument.getValue().method()); + assertTrue( + argument + .getValue() + .uri() + .getPath() + .contains("the_org_id/sources/my_source/stream/stream_id/close")); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } + + @Test + public void testDeleteDocument() throws IOException, InterruptedException { + client.deleteDocument("my_source", document().uri, true); + verify(httpClient) + .send(argument.capture(), any(HttpResponse.BodyHandlers.ofString().getClass())); + + assertEquals("DELETE", argument.getValue().method()); + assertTrue( + argument.getValue().uri().getPath().contains("the_org_id/sources/my_source/documents")); + assertTrue(argument.getValue().uri().getQuery().contains("deleteChildren=true")); + assertTrue( + argument + .getValue() + .uri() + .getQuery() + .contains(String.format("documentId=%s", document().uri))); + assertApplicationJsonHeader(); + assertAuthorizationHeader(); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/PlatformUrlBuilderTest.java b/src/test/java/com/coveo/pushapiclient/PlatformUrlBuilderTest.java index 718fb120..adb32378 100644 --- a/src/test/java/com/coveo/pushapiclient/PlatformUrlBuilderTest.java +++ b/src/test/java/com/coveo/pushapiclient/PlatformUrlBuilderTest.java @@ -1,73 +1,63 @@ package com.coveo.pushapiclient; +import static org.junit.Assert.*; + import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - public class PlatformUrlBuilderTest { - private PlatformUrlBuilder platformUrlBuilder; - - @Before - public void setup() { - platformUrlBuilder = new PlatformUrlBuilder(); - } - - @Test - public void testWithDefaultValues() { - PlatformUrl platformUrl = platformUrlBuilder.build(); - assertEquals( - "Should return default platform URL", - "https://platform.cloud.coveo.com", - platformUrl.getPlatformUrl()); - - assertEquals( - "Should return default API URL", - "https://api.cloud.coveo.com", - platformUrl.getApiUrl()); - } - - @Test - public void testWithNonDefaultRegion() { - PlatformUrl platformUrl = platformUrlBuilder.withRegion(Region.EU).build(); - assertEquals( - "Should return Europe platform URL", - "https://platform-eu.cloud.coveo.com", - platformUrl.getPlatformUrl()); - - assertEquals( - "Should return Europe API URL", - "https://api-eu.cloud.coveo.com", - platformUrl.getApiUrl()); - } - - @Test - public void testWithNonDefaultEnvironment() { - PlatformUrl platformUrl = platformUrlBuilder.withEnvironment(Environment.STAGING).build(); - assertEquals( - "Should return the staging platform URL", - "https://platformstg.cloud.coveo.com", - platformUrl.getPlatformUrl()); - - assertEquals( - "Should return the staging API URL", - "https://apistg.cloud.coveo.com", - platformUrl.getApiUrl()); - } - - @Test - public void testWithNonDefaultEnvironmentAndRegion() { - PlatformUrl platformUrl = platformUrlBuilder - .withEnvironment(Environment.DEVELOPMENT) - .withRegion(Region.EU) - .build(); - assertEquals( - "https://platformdev-eu.cloud.coveo.com", - platformUrl.getPlatformUrl()); - - assertEquals( - "https://apidev-eu.cloud.coveo.com", - platformUrl.getApiUrl()); - } + private PlatformUrlBuilder platformUrlBuilder; + + @Before + public void setup() { + platformUrlBuilder = new PlatformUrlBuilder(); + } + + @Test + public void testWithDefaultValues() { + PlatformUrl platformUrl = platformUrlBuilder.build(); + assertEquals( + "Should return default platform URL", + "https://platform.cloud.coveo.com", + platformUrl.getPlatformUrl()); + + assertEquals( + "Should return default API URL", "https://api.cloud.coveo.com", platformUrl.getApiUrl()); + } + + @Test + public void testWithNonDefaultRegion() { + PlatformUrl platformUrl = platformUrlBuilder.withRegion(Region.EU).build(); + assertEquals( + "Should return Europe platform URL", + "https://platform-eu.cloud.coveo.com", + platformUrl.getPlatformUrl()); + + assertEquals( + "Should return Europe API URL", "https://api-eu.cloud.coveo.com", platformUrl.getApiUrl()); + } + + @Test + public void testWithNonDefaultEnvironment() { + PlatformUrl platformUrl = platformUrlBuilder.withEnvironment(Environment.STAGING).build(); + assertEquals( + "Should return the staging platform URL", + "https://platformstg.cloud.coveo.com", + platformUrl.getPlatformUrl()); + + assertEquals( + "Should return the staging API URL", + "https://apistg.cloud.coveo.com", + platformUrl.getApiUrl()); + } + + @Test + public void testWithNonDefaultEnvironmentAndRegion() { + PlatformUrl platformUrl = + platformUrlBuilder.withEnvironment(Environment.DEVELOPMENT).withRegion(Region.EU).build(); + assertEquals("https://platformdev-eu.cloud.coveo.com", platformUrl.getPlatformUrl()); + + assertEquals("https://apidev-eu.cloud.coveo.com", platformUrl.getApiUrl()); + } } diff --git a/src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java b/src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java index 2a214f7e..99fd43cb 100644 --- a/src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java +++ b/src/test/java/com/coveo/pushapiclient/PushServiceInternalTest.java @@ -1,5 +1,11 @@ package com.coveo.pushapiclient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.coveo.pushapiclient.exceptions.NoOpenStreamException; +import java.io.IOException; +import java.net.http.HttpResponse; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -7,69 +13,56 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import com.coveo.pushapiclient.exceptions.NoOpenStreamException; - -import java.io.IOException; -import java.net.http.HttpResponse; - -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - public class PushServiceInternalTest { - @Mock - private DocumentUploadQueue queue; - - @InjectMocks - private PushServiceInternal service; - - @Mock - private HttpResponse httpResponse; - - private AutoCloseable closeable; - private DocumentBuilder documentA; - private DocumentBuilder documentB; - private DeleteDocument documentC; - - @Before - public void setUp() throws Exception { - documentA = new DocumentBuilder("https://my.document.uri?ref=1", "My first document title"); - documentB = new DocumentBuilder("https://my.document.uri?ref=2", "My second document title"); - documentC = new DeleteDocument("https://my.document.uri?ref=3"); - - closeable = MockitoAnnotations.openMocks(this); - - } - - @After - public void closeService() throws Exception { - closeable.close(); - } - - @Test - public void testShouldAddNewDocumentToQueue() throws IOException, InterruptedException { - service.addOrUpdate(documentA); - service.addOrUpdate(documentB); - - verify(this.queue, times(1)).add(documentA); - verify(this.queue, times(1)).add(documentB); - } - - @Test - public void testAddShouldAddDocumentToDeleteToQueue() throws IOException, InterruptedException { - service.delete(documentC); - - verify(queue, times(1)).add(documentC); - } - - @Test - public void testCloseShouldFlushBufferedDocuments() - throws IOException, InterruptedException, NoOpenStreamException { - service.addOrUpdate(documentA); - service.addOrUpdate(documentB); - service.delete(documentC); - service.close(); - - verify(queue, times(1)).flush(); - } - -} \ No newline at end of file + @Mock private DocumentUploadQueue queue; + + @InjectMocks private PushServiceInternal service; + + @Mock private HttpResponse httpResponse; + + private AutoCloseable closeable; + private DocumentBuilder documentA; + private DocumentBuilder documentB; + private DeleteDocument documentC; + + @Before + public void setUp() throws Exception { + documentA = new DocumentBuilder("https://my.document.uri?ref=1", "My first document title"); + documentB = new DocumentBuilder("https://my.document.uri?ref=2", "My second document title"); + documentC = new DeleteDocument("https://my.document.uri?ref=3"); + + closeable = MockitoAnnotations.openMocks(this); + } + + @After + public void closeService() throws Exception { + closeable.close(); + } + + @Test + public void testShouldAddNewDocumentToQueue() throws IOException, InterruptedException { + service.addOrUpdate(documentA); + service.addOrUpdate(documentB); + + verify(this.queue, times(1)).add(documentA); + verify(this.queue, times(1)).add(documentB); + } + + @Test + public void testAddShouldAddDocumentToDeleteToQueue() throws IOException, InterruptedException { + service.delete(documentC); + + verify(queue, times(1)).add(documentC); + } + + @Test + public void testCloseShouldFlushBufferedDocuments() + throws IOException, InterruptedException, NoOpenStreamException { + service.addOrUpdate(documentA); + service.addOrUpdate(documentB); + service.delete(documentC); + service.close(); + + verify(queue, times(1)).flush(); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/SecurityIdentityBatchConfigTest.java b/src/test/java/com/coveo/pushapiclient/SecurityIdentityBatchConfigTest.java index 3a54e9c5..c2391473 100644 --- a/src/test/java/com/coveo/pushapiclient/SecurityIdentityBatchConfigTest.java +++ b/src/test/java/com/coveo/pushapiclient/SecurityIdentityBatchConfigTest.java @@ -1,54 +1,54 @@ package com.coveo.pushapiclient; +import static org.junit.Assert.*; + import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - public class SecurityIdentityBatchConfigTest { - private SecurityIdentityBatchConfig config1; - private SecurityIdentityBatchConfig config2; - private SecurityIdentityBatchConfig config3; - private SecurityIdentityBatchConfig config4; - private SecurityIdentityBatchConfig config5; - - @Before - public void setUp() { - config1 = new SecurityIdentityBatchConfig("some_file_id", 123L); - config2 = new SecurityIdentityBatchConfig("some_file_id", 123L); - config3 = new SecurityIdentityBatchConfig("some_other_file_id", 123L); - config4 = new SecurityIdentityBatchConfig("some_file_id", 456L); - config5 = config1; - } - - @Test - public void testToString() { - assertEquals(config1.toString(), config1.toString()); - assertEquals(config1.toString(), config2.toString()); - assertEquals(config1.toString(), config5.toString()); - assertEquals(config3.toString(), config3.toString()); - assertNotEquals(config1.toString(), config3.toString()); - assertNotEquals(config3.toString(), config4.toString()); - } - - @Test - public void testEquals() { - assertFalse(config1.equals(null)); - assertTrue(config1.equals(config1)); - assertTrue(config1.equals(config2)); - assertTrue(config1.equals(config5)); - assertFalse(config1.equals(config3)); - assertFalse(config3.equals(config4)); - } - - @Test - public void testHashCode() { - assertEquals(config1.hashCode(), config1.hashCode()); - assertEquals(config1.hashCode(), config2.hashCode()); - assertEquals(config1.hashCode(), config5.hashCode()); - assertEquals(config3.hashCode(), config3.hashCode()); - assertNotEquals(config1.hashCode(), config3.hashCode()); - assertNotEquals(config3.hashCode(), config4.hashCode()); - } -} \ No newline at end of file + private SecurityIdentityBatchConfig config1; + private SecurityIdentityBatchConfig config2; + private SecurityIdentityBatchConfig config3; + private SecurityIdentityBatchConfig config4; + private SecurityIdentityBatchConfig config5; + + @Before + public void setUp() { + config1 = new SecurityIdentityBatchConfig("some_file_id", 123L); + config2 = new SecurityIdentityBatchConfig("some_file_id", 123L); + config3 = new SecurityIdentityBatchConfig("some_other_file_id", 123L); + config4 = new SecurityIdentityBatchConfig("some_file_id", 456L); + config5 = config1; + } + + @Test + public void testToString() { + assertEquals(config1.toString(), config1.toString()); + assertEquals(config1.toString(), config2.toString()); + assertEquals(config1.toString(), config5.toString()); + assertEquals(config3.toString(), config3.toString()); + assertNotEquals(config1.toString(), config3.toString()); + assertNotEquals(config3.toString(), config4.toString()); + } + + @Test + public void testEquals() { + assertFalse(config1.equals(null)); + assertTrue(config1.equals(config1)); + assertTrue(config1.equals(config2)); + assertTrue(config1.equals(config5)); + assertFalse(config1.equals(config3)); + assertFalse(config3.equals(config4)); + } + + @Test + public void testHashCode() { + assertEquals(config1.hashCode(), config1.hashCode()); + assertEquals(config1.hashCode(), config2.hashCode()); + assertEquals(config1.hashCode(), config5.hashCode()); + assertEquals(config3.hashCode(), config3.hashCode()); + assertNotEquals(config1.hashCode(), config3.hashCode()); + assertNotEquals(config3.hashCode(), config4.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptionsTest.java b/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptionsTest.java index b4018d4b..f8834a39 100644 --- a/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptionsTest.java +++ b/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteOptionsTest.java @@ -1,57 +1,57 @@ package com.coveo.pushapiclient; +import static org.junit.Assert.*; + import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - public class SecurityIdentityDeleteOptionsTest { - private SecurityIdentityDeleteOptions opt1; - private SecurityIdentityDeleteOptions opt2; - private SecurityIdentityDeleteOptions opt3; - private SecurityIdentityDeleteOptions opt4; - private SecurityIdentityDeleteOptions opt5; - - @Before - public void setUp() { - opt1 = new SecurityIdentityDeleteOptions(123, 123L); - opt2 = new SecurityIdentityDeleteOptions(123, 123L); - opt3 = new SecurityIdentityDeleteOptions(456, 123L); - opt4 = new SecurityIdentityDeleteOptions(123, 456L); - opt5 = opt1; - } - - @Test - public void testToString() { - assertEquals(opt1.toString(), opt1.toString()); - assertEquals(opt1.toString(), opt2.toString()); - assertEquals(opt1.toString(), opt5.toString()); - assertEquals(opt3.toString(), opt3.toString()); - assertNotEquals(opt1.toString(), opt3.toString()); - assertNotEquals(opt3.toString(), opt4.toString()); - } - - @Test - public void testEquals() { - assertTrue(opt1.equals(opt1)); - assertTrue(opt1.equals(opt2)); - assertTrue(opt1.equals(opt5)); - assertFalse(opt1.equals(opt3)); - assertFalse(opt1.equals(opt4)); - assertFalse(opt3.equals(opt4)); - assertFalse(opt1.equals(null)); - } - - @Test - public void testHashCode() { - assertEquals(opt1.hashCode(), opt1.hashCode()); - assertEquals(opt1.hashCode(), opt2.hashCode()); - assertEquals(opt1.hashCode(), opt5.hashCode()); - assertEquals(opt3.hashCode(), opt3.hashCode()); - assertEquals(opt4.hashCode(), opt4.hashCode()); - assertNotEquals(opt1.hashCode(), opt3.hashCode()); - assertNotEquals(opt1.hashCode(), opt4.hashCode()); - assertNotEquals(opt3.hashCode(), opt4.hashCode()); - } -} \ No newline at end of file + private SecurityIdentityDeleteOptions opt1; + private SecurityIdentityDeleteOptions opt2; + private SecurityIdentityDeleteOptions opt3; + private SecurityIdentityDeleteOptions opt4; + private SecurityIdentityDeleteOptions opt5; + + @Before + public void setUp() { + opt1 = new SecurityIdentityDeleteOptions(123, 123L); + opt2 = new SecurityIdentityDeleteOptions(123, 123L); + opt3 = new SecurityIdentityDeleteOptions(456, 123L); + opt4 = new SecurityIdentityDeleteOptions(123, 456L); + opt5 = opt1; + } + + @Test + public void testToString() { + assertEquals(opt1.toString(), opt1.toString()); + assertEquals(opt1.toString(), opt2.toString()); + assertEquals(opt1.toString(), opt5.toString()); + assertEquals(opt3.toString(), opt3.toString()); + assertNotEquals(opt1.toString(), opt3.toString()); + assertNotEquals(opt3.toString(), opt4.toString()); + } + + @Test + public void testEquals() { + assertTrue(opt1.equals(opt1)); + assertTrue(opt1.equals(opt2)); + assertTrue(opt1.equals(opt5)); + assertFalse(opt1.equals(opt3)); + assertFalse(opt1.equals(opt4)); + assertFalse(opt3.equals(opt4)); + assertFalse(opt1.equals(null)); + } + + @Test + public void testHashCode() { + assertEquals(opt1.hashCode(), opt1.hashCode()); + assertEquals(opt1.hashCode(), opt2.hashCode()); + assertEquals(opt1.hashCode(), opt5.hashCode()); + assertEquals(opt3.hashCode(), opt3.hashCode()); + assertEquals(opt4.hashCode(), opt4.hashCode()); + assertNotEquals(opt1.hashCode(), opt3.hashCode()); + assertNotEquals(opt1.hashCode(), opt4.hashCode()); + assertNotEquals(opt3.hashCode(), opt4.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteTest.java b/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteTest.java index 90b06ea6..0cb1fe3d 100644 --- a/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteTest.java +++ b/src/test/java/com/coveo/pushapiclient/SecurityIdentityDeleteTest.java @@ -1,71 +1,68 @@ package com.coveo.pushapiclient; -import org.junit.Before; -import org.junit.Test; +import static org.junit.Assert.*; import java.util.HashMap; import java.util.Map; - -import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; public class SecurityIdentityDeleteTest { - private SecurityIdentityDelete sid1; - private SecurityIdentityDelete sid2; - private SecurityIdentityDelete sid3; - private SecurityIdentityDelete sid4; - private SecurityIdentityDelete sid5; - - @Before - public void setUp() { - Map info1 = new HashMap<>(); - Map info2 = new HashMap<>(); - info1.put("key1", "value1"); - info1.put("key2", "value2"); - info2.put("key2.1", "value2.1"); - - IdentityModel id1 = new IdentityModel("some_name", SecurityIdentityType.USER, info1); - IdentityModel id3 = new IdentityModel("some_name", SecurityIdentityType.GROUP, info2); - IdentityModel id4 = new IdentityModel("some_other_name", SecurityIdentityType.USER, null); + private SecurityIdentityDelete sid1; + private SecurityIdentityDelete sid2; + private SecurityIdentityDelete sid3; + private SecurityIdentityDelete sid4; + private SecurityIdentityDelete sid5; - sid1 = new SecurityIdentityDelete(id1); - sid2 = new SecurityIdentityDelete(id1); - sid3 = new SecurityIdentityDelete(id3); - sid4 = new SecurityIdentityDelete(id4); - sid5 = sid1; + @Before + public void setUp() { + Map info1 = new HashMap<>(); + Map info2 = new HashMap<>(); + info1.put("key1", "value1"); + info1.put("key2", "value2"); + info2.put("key2.1", "value2.1"); - } + IdentityModel id1 = new IdentityModel("some_name", SecurityIdentityType.USER, info1); + IdentityModel id3 = new IdentityModel("some_name", SecurityIdentityType.GROUP, info2); + IdentityModel id4 = new IdentityModel("some_other_name", SecurityIdentityType.USER, null); - @Test - public void testToString() { - assertEquals(sid1.toString(), sid1.toString()); - assertEquals(sid1.toString(), sid2.toString()); - assertEquals(sid1.toString(), sid5.toString()); - assertEquals(sid2.toString(), sid5.toString()); - assertEquals(sid3.toString(), sid3.toString()); - assertEquals(sid4.toString(), sid4.toString()); - assertNotEquals(sid1.toString(), sid3.toString()); - assertNotEquals(sid2.toString(), sid4.toString()); - } + sid1 = new SecurityIdentityDelete(id1); + sid2 = new SecurityIdentityDelete(id1); + sid3 = new SecurityIdentityDelete(id3); + sid4 = new SecurityIdentityDelete(id4); + sid5 = sid1; + } - @Test - public void testEquals() { - assertTrue(sid1.equals(sid1)); - assertTrue(sid1.equals(sid2)); - assertTrue(sid1.equals(sid5)); - assertTrue(sid3.equals(sid3)); - assertFalse(sid1.equals(sid3)); - assertFalse(sid3.equals(sid4)); - assertFalse(sid1.equals(null)); - } + @Test + public void testToString() { + assertEquals(sid1.toString(), sid1.toString()); + assertEquals(sid1.toString(), sid2.toString()); + assertEquals(sid1.toString(), sid5.toString()); + assertEquals(sid2.toString(), sid5.toString()); + assertEquals(sid3.toString(), sid3.toString()); + assertEquals(sid4.toString(), sid4.toString()); + assertNotEquals(sid1.toString(), sid3.toString()); + assertNotEquals(sid2.toString(), sid4.toString()); + } - @Test - public void testHashCode() { - assertEquals(sid1.hashCode(), sid1.hashCode()); - assertEquals(sid1.hashCode(), sid2.hashCode()); - assertEquals(sid1.hashCode(), sid5.hashCode()); - assertNotEquals(sid1.hashCode(), sid3.hashCode()); - assertNotEquals(sid3.hashCode(), sid4.hashCode()); + @Test + public void testEquals() { + assertTrue(sid1.equals(sid1)); + assertTrue(sid1.equals(sid2)); + assertTrue(sid1.equals(sid5)); + assertTrue(sid3.equals(sid3)); + assertFalse(sid1.equals(sid3)); + assertFalse(sid3.equals(sid4)); + assertFalse(sid1.equals(null)); + } - } -} \ No newline at end of file + @Test + public void testHashCode() { + assertEquals(sid1.hashCode(), sid1.hashCode()); + assertEquals(sid1.hashCode(), sid2.hashCode()); + assertEquals(sid1.hashCode(), sid5.hashCode()); + assertNotEquals(sid1.hashCode(), sid3.hashCode()); + assertNotEquals(sid3.hashCode(), sid4.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java b/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java index 5779b240..d850c5e3 100644 --- a/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java +++ b/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java @@ -1,5 +1,12 @@ package com.coveo.pushapiclient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.coveo.pushapiclient.exceptions.NoOpenStreamException; +import java.io.IOException; +import java.net.http.HttpResponse; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -7,90 +14,76 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import com.coveo.pushapiclient.exceptions.NoOpenStreamException; - -import java.io.IOException; -import java.net.http.HttpResponse; - -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class StreamServiceInternalTest { - @Mock - private StreamEnabledSource source; - - @Mock - private DocumentUploadQueue queue; + @Mock private StreamEnabledSource source; - @Mock - private PlatformClient platformClient; + @Mock private DocumentUploadQueue queue; - @InjectMocks - private StreamServiceInternal service; + @Mock private PlatformClient platformClient; - @Mock - private HttpResponse httpResponse; + @InjectMocks private StreamServiceInternal service; - private AutoCloseable closeable; - private DocumentBuilder documentA; - private DocumentBuilder documentB; + @Mock private HttpResponse httpResponse; - @Before - public void setUp() throws Exception { - documentA = new DocumentBuilder("https://my.document.uri?ref=1", "My first document title"); - documentB = new DocumentBuilder("https://my.document.uri?ref=2", "My second document title"); + private AutoCloseable closeable; + private DocumentBuilder documentA; + private DocumentBuilder documentB; - closeable = MockitoAnnotations.openMocks(this); + @Before + public void setUp() throws Exception { + documentA = new DocumentBuilder("https://my.document.uri?ref=1", "My first document title"); + documentB = new DocumentBuilder("https://my.document.uri?ref=2", "My second document title"); - when(httpResponse.body()).thenReturn("{\"streamId\": \"stream-id\"}"); - when(platformClient.openStream("my-source-id")).thenReturn(httpResponse); - when(source.getId()).thenReturn("my-source-id"); - } + closeable = MockitoAnnotations.openMocks(this); - @After - public void closeService() throws Exception { - closeable.close(); - } + when(httpResponse.body()).thenReturn("{\"streamId\": \"stream-id\"}"); + when(platformClient.openStream("my-source-id")).thenReturn(httpResponse); + when(source.getId()).thenReturn("my-source-id"); + } - @Test - public void testAddShouldOpenANewStream() throws IOException, InterruptedException { - service.add(documentA); - service.add(documentB); + @After + public void closeService() throws Exception { + closeable.close(); + } - verify(this.platformClient, times(1)).openStream("my-source-id"); - } + @Test + public void testAddShouldOpenANewStream() throws IOException, InterruptedException { + service.add(documentA); + service.add(documentB); - @Test - public void testAddShouldAddDocumentToQueue() throws IOException, InterruptedException { - service.add(documentA); - service.add(documentB); + verify(this.platformClient, times(1)).openStream("my-source-id"); + } - verify(queue, times(1)).add(documentA); - verify(queue, times(1)).add(documentB); - } + @Test + public void testAddShouldAddDocumentToQueue() throws IOException, InterruptedException { + service.add(documentA); + service.add(documentB); - @Test - public void testCloseShouldCloseOpenStream() throws IOException, InterruptedException, NoOpenStreamException { - service.add(documentA); - service.close(); + verify(queue, times(1)).add(documentA); + verify(queue, times(1)).add(documentB); + } - verify(platformClient, times(1)).closeStream("my-source-id", "stream-id"); - } + @Test + public void testCloseShouldCloseOpenStream() + throws IOException, InterruptedException, NoOpenStreamException { + service.add(documentA); + service.close(); - @Test - public void testCloseShouldFlushBufferedDocuments() - throws IOException, InterruptedException, NoOpenStreamException { - service.add(documentA); - service.close(); + verify(platformClient, times(1)).closeStream("my-source-id", "stream-id"); + } - verify(queue, times(1)).flush(); - } + @Test + public void testCloseShouldFlushBufferedDocuments() + throws IOException, InterruptedException, NoOpenStreamException { + service.add(documentA); + service.close(); - @Test(expected = NoOpenStreamException.class) - public void givenNoOpenStream_whenClose_thenShouldThrow() - throws IOException, InterruptedException, NoOpenStreamException { - service.close(); - } + verify(queue, times(1)).flush(); + } -} \ No newline at end of file + @Test(expected = NoOpenStreamException.class) + public void givenNoOpenStream_whenClose_thenShouldThrow() + throws IOException, InterruptedException, NoOpenStreamException { + service.close(); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/StringSubscriber.java b/src/test/java/com/coveo/pushapiclient/StringSubscriber.java index e061154d..f542d1cc 100644 --- a/src/test/java/com/coveo/pushapiclient/StringSubscriber.java +++ b/src/test/java/com/coveo/pushapiclient/StringSubscriber.java @@ -1,8 +1,6 @@ package com.coveo.pushapiclient; - import com.google.gson.Gson; - import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.ByteBuffer; @@ -14,40 +12,42 @@ class StringSubscriber implements Flow.Subscriber { - HttpResponse.BodySubscriber wrapped; - - public StringSubscriber(HttpResponse.BodySubscriber wrapped) { - this.wrapped = wrapped; - } - - public static Map toMap(Optional bodyPublisher) { - return bodyPublisher.map(p -> { - var bodySubscriber = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8); - var flowSubscriber = new StringSubscriber(bodySubscriber); - p.subscribe(flowSubscriber); - String requestBodyAsString = bodySubscriber.getBody().toCompletableFuture().join(); - return new Gson().fromJson(requestBodyAsString, Map.class); - }).get(); - } - - @Override - public void onSubscribe(Flow.Subscription subscription) { - wrapped.onSubscribe(subscription); - } - - @Override - public void onNext(ByteBuffer item) { - wrapped.onNext(List.of(item)); - } - - @Override - public void onError(Throwable throwable) { - wrapped.onError(throwable); - } - - @Override - public void onComplete() { - wrapped.onComplete(); - } + HttpResponse.BodySubscriber wrapped; + + public StringSubscriber(HttpResponse.BodySubscriber wrapped) { + this.wrapped = wrapped; + } + + public static Map toMap(Optional bodyPublisher) { + return bodyPublisher + .map( + p -> { + var bodySubscriber = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8); + var flowSubscriber = new StringSubscriber(bodySubscriber); + p.subscribe(flowSubscriber); + String requestBodyAsString = bodySubscriber.getBody().toCompletableFuture().join(); + return new Gson().fromJson(requestBodyAsString, Map.class); + }) + .get(); + } + + @Override + public void onSubscribe(Flow.Subscription subscription) { + wrapped.onSubscribe(subscription); + } + + @Override + public void onNext(ByteBuffer item) { + wrapped.onNext(List.of(item)); + } + + @Override + public void onError(Throwable throwable) { + wrapped.onError(throwable); + } + + @Override + public void onComplete() { + wrapped.onComplete(); + } } - diff --git a/src/test/java/com/coveo/pushapiclient/UserSecurityIdentityBuilderTest.java b/src/test/java/com/coveo/pushapiclient/UserSecurityIdentityBuilderTest.java index 65ecd53d..bca5be0b 100644 --- a/src/test/java/com/coveo/pushapiclient/UserSecurityIdentityBuilderTest.java +++ b/src/test/java/com/coveo/pushapiclient/UserSecurityIdentityBuilderTest.java @@ -1,84 +1,85 @@ package com.coveo.pushapiclient; -import org.junit.Before; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; -public class UserSecurityIdentityBuilderTest { - - private UserSecurityIdentityBuilder usib1; - private UserSecurityIdentityBuilder usib2; - private UserSecurityIdentityBuilder usib3; - private UserSecurityIdentityBuilder usib4; - private UserSecurityIdentityBuilder usib5; - - @Before - public void setUp() { - String[] id1 = new String[]{"identity1", "identity2"}; - String[] id2 = new String[]{"identity2", "identity3"}; - - usib1 = new UserSecurityIdentityBuilder(id1, "some_sec_provider"); - usib2 = new UserSecurityIdentityBuilder(id1, "some_sec_provider"); - usib3 = new UserSecurityIdentityBuilder(id2, "some_sec_provider"); - usib4 = new UserSecurityIdentityBuilder(id1, "some_other_sec_provider"); - usib5 = usib1; - } - - @Test - public void testSingleIdentity() { - SecurityIdentity identityBuilt = new UserSecurityIdentityBuilder("bob@foo.com").build()[0]; - - assertEquals("bob@foo.com", identityBuilt.identity); - assertEquals(SecurityIdentityType.USER, identityBuilt.identityType); - assertEquals("Email Security Provider", identityBuilt.securityProvider); - - } - - @Test - public void testMultipleIdentities() { - SecurityIdentity[] identitiesBuilt = new UserSecurityIdentityBuilder(new String[]{"bob@foo.com", "john@foo.com"}).build(); - - assertEquals("bob@foo.com", identitiesBuilt[0].identity); - assertEquals("john@foo.com", identitiesBuilt[1].identity); - } - - @Test - public void testSecurityProvider() { - SecurityIdentity identityBuilt = new UserSecurityIdentityBuilder("bob@foo.com", "my provider").build()[0]; - - assertEquals("my provider", identityBuilt.securityProvider); - } - - @Test - public void testToString() { - assertEquals(usib1.toString(), usib1.toString()); - assertEquals(usib1.toString(), usib2.toString()); - assertEquals(usib1.toString(), usib5.toString()); - assertNotEquals(usib1.toString(), usib3.toString()); - assertNotEquals(usib3.toString(), usib4.toString()); - } +import org.junit.Before; +import org.junit.Test; - @Test - public void testEquals() { - assertTrue(usib1.equals(usib1)); - assertTrue(usib1.equals(usib2)); - assertTrue(usib1.equals(usib5)); - assertFalse(usib3.equals(usib1)); - assertFalse(usib3.equals(usib4)); - assertFalse(usib1.equals(null)); - } +public class UserSecurityIdentityBuilderTest { - @Test - public void testHashCode() { - assertEquals(usib1.hashCode(), usib1.hashCode()); - assertEquals(usib1.hashCode(), usib2.hashCode()); - assertEquals(usib1.hashCode(), usib5.hashCode()); - assertEquals(usib3.hashCode(), usib3.hashCode()); - assertNotEquals(usib1.hashCode(), usib3.hashCode()); - assertNotEquals(usib3.hashCode(), usib4.hashCode()); - } -} \ No newline at end of file + private UserSecurityIdentityBuilder usib1; + private UserSecurityIdentityBuilder usib2; + private UserSecurityIdentityBuilder usib3; + private UserSecurityIdentityBuilder usib4; + private UserSecurityIdentityBuilder usib5; + + @Before + public void setUp() { + String[] id1 = new String[] {"identity1", "identity2"}; + String[] id2 = new String[] {"identity2", "identity3"}; + + usib1 = new UserSecurityIdentityBuilder(id1, "some_sec_provider"); + usib2 = new UserSecurityIdentityBuilder(id1, "some_sec_provider"); + usib3 = new UserSecurityIdentityBuilder(id2, "some_sec_provider"); + usib4 = new UserSecurityIdentityBuilder(id1, "some_other_sec_provider"); + usib5 = usib1; + } + + @Test + public void testSingleIdentity() { + SecurityIdentity identityBuilt = new UserSecurityIdentityBuilder("bob@foo.com").build()[0]; + + assertEquals("bob@foo.com", identityBuilt.identity); + assertEquals(SecurityIdentityType.USER, identityBuilt.identityType); + assertEquals("Email Security Provider", identityBuilt.securityProvider); + } + + @Test + public void testMultipleIdentities() { + SecurityIdentity[] identitiesBuilt = + new UserSecurityIdentityBuilder(new String[] {"bob@foo.com", "john@foo.com"}).build(); + + assertEquals("bob@foo.com", identitiesBuilt[0].identity); + assertEquals("john@foo.com", identitiesBuilt[1].identity); + } + + @Test + public void testSecurityProvider() { + SecurityIdentity identityBuilt = + new UserSecurityIdentityBuilder("bob@foo.com", "my provider").build()[0]; + + assertEquals("my provider", identityBuilt.securityProvider); + } + + @Test + public void testToString() { + assertEquals(usib1.toString(), usib1.toString()); + assertEquals(usib1.toString(), usib2.toString()); + assertEquals(usib1.toString(), usib5.toString()); + assertNotEquals(usib1.toString(), usib3.toString()); + assertNotEquals(usib3.toString(), usib4.toString()); + } + + @Test + public void testEquals() { + assertTrue(usib1.equals(usib1)); + assertTrue(usib1.equals(usib2)); + assertTrue(usib1.equals(usib5)); + assertFalse(usib3.equals(usib1)); + assertFalse(usib3.equals(usib4)); + assertFalse(usib1.equals(null)); + } + + @Test + public void testHashCode() { + assertEquals(usib1.hashCode(), usib1.hashCode()); + assertEquals(usib1.hashCode(), usib2.hashCode()); + assertEquals(usib1.hashCode(), usib5.hashCode()); + assertEquals(usib3.hashCode(), usib3.hashCode()); + assertNotEquals(usib1.hashCode(), usib3.hashCode()); + assertNotEquals(usib3.hashCode(), usib4.hashCode()); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilderTest.java b/src/test/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilderTest.java index a3437c6d..2ed2aab9 100644 --- a/src/test/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilderTest.java +++ b/src/test/java/com/coveo/pushapiclient/VirtualGroupSecurityIdentityBuilderTest.java @@ -1,77 +1,80 @@ package com.coveo.pushapiclient; -import org.junit.Before; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; + public class VirtualGroupSecurityIdentityBuilderTest { - private VirtualGroupSecurityIdentityBuilder vgsib1; - private VirtualGroupSecurityIdentityBuilder vgsib2; - private VirtualGroupSecurityIdentityBuilder vgsib3; - private VirtualGroupSecurityIdentityBuilder vgsib4; - private VirtualGroupSecurityIdentityBuilder vgsib5; + private VirtualGroupSecurityIdentityBuilder vgsib1; + private VirtualGroupSecurityIdentityBuilder vgsib2; + private VirtualGroupSecurityIdentityBuilder vgsib3; + private VirtualGroupSecurityIdentityBuilder vgsib4; + private VirtualGroupSecurityIdentityBuilder vgsib5; - @Before - public void setUp() { - String[] id1 = new String[]{"identity1", "identity2"}; - String[] id2 = new String[]{"identity2", "identity3"}; + @Before + public void setUp() { + String[] id1 = new String[] {"identity1", "identity2"}; + String[] id2 = new String[] {"identity2", "identity3"}; - vgsib1 = new VirtualGroupSecurityIdentityBuilder(id1, "some_sec_provider"); - vgsib2 = new VirtualGroupSecurityIdentityBuilder(id1, "some_sec_provider"); - vgsib3 = new VirtualGroupSecurityIdentityBuilder(id2, "some_sec_provider"); - vgsib4 = new VirtualGroupSecurityIdentityBuilder(id1, "some_other_sec_provider"); - vgsib5 = vgsib1; - } - - @Test - public void testSingleIdentity() { - SecurityIdentity identityBuilt = new VirtualGroupSecurityIdentityBuilder("bob@foo.com", "my provider").build()[0]; + vgsib1 = new VirtualGroupSecurityIdentityBuilder(id1, "some_sec_provider"); + vgsib2 = new VirtualGroupSecurityIdentityBuilder(id1, "some_sec_provider"); + vgsib3 = new VirtualGroupSecurityIdentityBuilder(id2, "some_sec_provider"); + vgsib4 = new VirtualGroupSecurityIdentityBuilder(id1, "some_other_sec_provider"); + vgsib5 = vgsib1; + } - assertEquals("bob@foo.com", identityBuilt.identity); - assertEquals(SecurityIdentityType.VIRTUAL_GROUP, identityBuilt.identityType); - assertEquals("my provider", identityBuilt.securityProvider); + @Test + public void testSingleIdentity() { + SecurityIdentity identityBuilt = + new VirtualGroupSecurityIdentityBuilder("bob@foo.com", "my provider").build()[0]; - } + assertEquals("bob@foo.com", identityBuilt.identity); + assertEquals(SecurityIdentityType.VIRTUAL_GROUP, identityBuilt.identityType); + assertEquals("my provider", identityBuilt.securityProvider); + } - @Test - public void testMultipleIdentities() { - SecurityIdentity[] identitiesBuilt = new VirtualGroupSecurityIdentityBuilder(new String[]{"bob@foo.com", "john@foo.com"}, "my provider").build(); + @Test + public void testMultipleIdentities() { + SecurityIdentity[] identitiesBuilt = + new VirtualGroupSecurityIdentityBuilder( + new String[] {"bob@foo.com", "john@foo.com"}, "my provider") + .build(); - assertEquals("bob@foo.com", identitiesBuilt[0].identity); - assertEquals("john@foo.com", identitiesBuilt[1].identity); - } + assertEquals("bob@foo.com", identitiesBuilt[0].identity); + assertEquals("john@foo.com", identitiesBuilt[1].identity); + } - @Test - public void testToString() { - assertEquals(vgsib1.toString(), vgsib1.toString()); - assertEquals(vgsib1.toString(), vgsib2.toString()); - assertEquals(vgsib1.toString(), vgsib5.toString()); - assertNotEquals(vgsib1.toString(), vgsib3.toString()); - assertNotEquals(vgsib3.toString(), vgsib4.toString()); - } + @Test + public void testToString() { + assertEquals(vgsib1.toString(), vgsib1.toString()); + assertEquals(vgsib1.toString(), vgsib2.toString()); + assertEquals(vgsib1.toString(), vgsib5.toString()); + assertNotEquals(vgsib1.toString(), vgsib3.toString()); + assertNotEquals(vgsib3.toString(), vgsib4.toString()); + } - @Test - public void testEquals() { - assertTrue(vgsib1.equals(vgsib1)); - assertTrue(vgsib1.equals(vgsib2)); - assertTrue(vgsib1.equals(vgsib5)); - assertFalse(vgsib3.equals(vgsib1)); - assertFalse(vgsib3.equals(vgsib4)); - assertFalse(vgsib1.equals(null)); - } + @Test + public void testEquals() { + assertTrue(vgsib1.equals(vgsib1)); + assertTrue(vgsib1.equals(vgsib2)); + assertTrue(vgsib1.equals(vgsib5)); + assertFalse(vgsib3.equals(vgsib1)); + assertFalse(vgsib3.equals(vgsib4)); + assertFalse(vgsib1.equals(null)); + } - @Test - public void testHashCode() { - assertEquals(vgsib1.hashCode(), vgsib1.hashCode()); - assertEquals(vgsib1.hashCode(), vgsib2.hashCode()); - assertEquals(vgsib1.hashCode(), vgsib5.hashCode()); - assertEquals(vgsib3.hashCode(), vgsib3.hashCode()); - assertNotEquals(vgsib1.hashCode(), vgsib3.hashCode()); - assertNotEquals(vgsib3.hashCode(), vgsib4.hashCode()); - } -} \ No newline at end of file + @Test + public void testHashCode() { + assertEquals(vgsib1.hashCode(), vgsib1.hashCode()); + assertEquals(vgsib1.hashCode(), vgsib2.hashCode()); + assertEquals(vgsib1.hashCode(), vgsib5.hashCode()); + assertEquals(vgsib3.hashCode(), vgsib3.hashCode()); + assertNotEquals(vgsib1.hashCode(), vgsib3.hashCode()); + assertNotEquals(vgsib3.hashCode(), vgsib4.hashCode()); + } +} From bc2af2e51c40978a92280f4926e711117e1c4c52 Mon Sep 17 00:00:00 2001 From: Houssein Dhayne <95109658+hdhayneCoveo@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:15:18 -0400 Subject: [PATCH 17/44] fix: in StreamService streamId was never set , with this PR , it is returned from StreamServiceInternal (#42) Co-authored-by: Yassine --- src/main/java/com/coveo/pushapiclient/StreamService.java | 2 +- .../java/com/coveo/pushapiclient/StreamServiceInternal.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/StreamService.java b/src/main/java/com/coveo/pushapiclient/StreamService.java index a536ded4..51ec841b 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamService.java +++ b/src/main/java/com/coveo/pushapiclient/StreamService.java @@ -69,7 +69,7 @@ public StreamService(StreamEnabledSource source) { * @throws IOException */ public void add(DocumentBuilder document) throws IOException, InterruptedException { - this.service.add(document); + this.streamId = this.service.add(document); } /** diff --git a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java index b0145504..e5579752 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java +++ b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java @@ -19,11 +19,12 @@ public StreamServiceInternal( this.platformClient = platformClient; } - public void add(DocumentBuilder document) throws IOException, InterruptedException { + public String add(DocumentBuilder document) throws IOException, InterruptedException { if (this.streamId == null) { this.streamId = this.getStreamId(); } queue.add(document); + return this.streamId; } public HttpResponse close() From f8e25dad5ea1ca2157853aaa831b2beaece7d15e Mon Sep 17 00:00:00 2001 From: Yassine Date: Mon, 12 Jun 2023 10:59:41 -0400 Subject: [PATCH 18/44] ci: fix typo in GH workflow (#45) --- .github/workflows/pr-title-semantic-lint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-title-semantic-lint.yml b/.github/workflows/pr-title-semantic-lint.yml index 96bf265e..2f50d6ed 100644 --- a/.github/workflows/pr-title-semantic-lint.yml +++ b/.github/workflows/pr-title-semantic-lint.yml @@ -1,11 +1,11 @@ name: PrTitleSemanticLint on: pull_request: - branches: [master] + branches: [main] types: [opened, edited, synchronize, reopened] jobs: Lint: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} steps: From a21ccb8891bce387a622d12594e6df2fcb12567e Mon Sep 17 00:00:00 2001 From: Yassine Date: Mon, 12 Jun 2023 14:46:41 -0400 Subject: [PATCH 19/44] ci: automate package publish (#47) https://coveord.atlassian.net/browse/LENS-907 --- .github/workflows/auto-approve-renovate.yml | 19 + .github/workflows/maven-publish.yml | 34 ++ .github/workflows/release.yml | 42 ++ package-lock.json | 431 +++++++++++++++++++- package.json | 8 +- pom.xml | 21 +- utils/get-token.mjs | 18 + 7 files changed, 554 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/auto-approve-renovate.yml create mode 100644 .github/workflows/maven-publish.yml create mode 100644 .github/workflows/release.yml create mode 100644 utils/get-token.mjs diff --git a/.github/workflows/auto-approve-renovate.yml b/.github/workflows/auto-approve-renovate.yml new file mode 100644 index 00000000..1ef4f095 --- /dev/null +++ b/.github/workflows/auto-approve-renovate.yml @@ -0,0 +1,19 @@ +name: Automated approval + +on: + pull_request: + types: + - opened + - reopened + - labeled + +jobs: + auto-approve: + runs-on: ubuntu-latest + if: (github.actor == 'developer-experience-bot[bot]') && (contains(join(github.event.pull_request.labels.*.name), 'snpashot')) + steps: + - name: auto-approve + id: auto-approve + uses: coveo/actions/auto-approve-action@main + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" \ No newline at end of file diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml new file mode 100644 index 00000000..e120740f --- /dev/null +++ b/.github/workflows/maven-publish.yml @@ -0,0 +1,34 @@ +# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created +# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path + +name: Maven Package + +on: + # TODO: remove after release. This is a fail safe in case this workflow does not get triggered + workflow_dispatch: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + server-id: github + + - name: Build with Maven + run: mvn -B clean package --file pom.xml + + - name: Publish to GitHub Packages Apache Maven + run: mvn deploy + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..f8e389a4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,42 @@ +name: Create release + +on: + push: + branches: + - main + +jobs: + release: + runs-on: ubuntu-latest + environment: 'Release' + steps: + - uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '18' + + - name: Install dependencies + run: npm ci + + - name: Get Release Token + run: npm run get-token + + - uses: actions/setup-java@v3 + name: Set up Java + with: + java-version: '11' + distribution: 'adopt' + + - name: Build Java package + run: mvn clean package + + - uses: google-github-actions/release-please-action@v3 + name: Release Java package + with: + release-type: maven + package-name: release-please-action + default-branch: main + pull-request-title-pattern: 'chore${scope}: release${component} ${version} [skip-ci]' + token: $RELEASE_TOKEN diff --git a/package-lock.json b/package-lock.json index 62b17eaf..0d5612dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,28 @@ "version": "1.0.0", "license": "Apache-2.0", "devDependencies": { - "@commitlint/config-conventional": "17.4.4" + "@actions/core": "^1.10.0", + "@commitlint/config-conventional": "17.4.4", + "@octokit/auth-app": "^4.0.9" + } + }, + "node_modules/@actions/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", + "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "dev": true, + "dependencies": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "node_modules/@actions/http-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", + "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", + "dev": true, + "dependencies": { + "tunnel": "^0.0.6" } }, "node_modules/@commitlint/config-conventional": { @@ -24,12 +45,200 @@ "node": ">=v14" } }, + "node_modules/@octokit/auth-app": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-4.0.13.tgz", + "integrity": "sha512-NBQkmR/Zsc+8fWcVIFrwDgNXS7f4XDrkd9LHdi9DPQw1NdGHLviLzRO2ZBwTtepnwHXW5VTrVU9eFGijMUqllg==", + "dev": true, + "dependencies": { + "@octokit/auth-oauth-app": "^5.0.0", + "@octokit/auth-oauth-user": "^2.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "deprecation": "^2.3.1", + "lru-cache": "^9.0.0", + "universal-github-app-jwt": "^1.1.1", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/auth-oauth-app": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-5.0.6.tgz", + "integrity": "sha512-SxyfIBfeFcWd9Z/m1xa4LENTQ3l1y6Nrg31k2Dcb1jS5ov7pmwMJZ6OGX8q3K9slRgVpeAjNA1ipOAMHkieqyw==", + "dev": true, + "dependencies": { + "@octokit/auth-oauth-device": "^4.0.0", + "@octokit/auth-oauth-user": "^2.0.0", + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", + "@types/btoa-lite": "^1.0.0", + "btoa-lite": "^1.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/auth-oauth-device": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-4.0.5.tgz", + "integrity": "sha512-XyhoWRTzf2ZX0aZ52a6Ew5S5VBAfwwx1QnC2Np6Et3MWQpZjlREIcbcvVZtkNuXp6Z9EeiSLSDUqm3C+aMEHzQ==", + "dev": true, + "dependencies": { + "@octokit/oauth-methods": "^2.0.0", + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/auth-oauth-user": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-2.1.2.tgz", + "integrity": "sha512-kkRqNmFe7s5GQcojE3nSlF+AzYPpPv7kvP/xYEnE57584pixaFBH8Vovt+w5Y3E4zWUEOxjdLItmBTFAWECPAg==", + "dev": true, + "dependencies": { + "@octokit/auth-oauth-device": "^4.0.0", + "@octokit/oauth-methods": "^2.0.0", + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", + "btoa-lite": "^1.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/endpoint": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", + "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", + "dev": true, + "dependencies": { + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/oauth-authorization-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-5.0.0.tgz", + "integrity": "sha512-y1WhN+ERDZTh0qZ4SR+zotgsQUE1ysKnvBt1hvDRB2WRzYtVKQjn97HEPzoehh66Fj9LwNdlZh+p6TJatT0zzg==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/oauth-methods": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-2.0.6.tgz", + "integrity": "sha512-l9Uml2iGN2aTWLZcm8hV+neBiFXAQ9+3sKiQe/sgumHlL6HDg0AQ8/l16xX/5jJvfxueqTW5CWbzd0MjnlfHZw==", + "dev": true, + "dependencies": { + "@octokit/oauth-authorization-url": "^5.0.0", + "@octokit/request": "^6.2.3", + "@octokit/request-error": "^3.0.3", + "@octokit/types": "^9.0.0", + "btoa-lite": "^1.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz", + "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==", + "dev": true + }, + "node_modules/@octokit/request": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.5.tgz", + "integrity": "sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==", + "dev": true, + "dependencies": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/request-error": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", + "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", + "dev": true, + "dependencies": { + "@octokit/types": "^9.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/types": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.1.tgz", + "integrity": "sha512-zfJzyXLHC42sWcn2kS+oZ/DRvFZBYCCbfInZtwp1Uopl1qh6pRg4NSP/wFX1xCOpXvEkctiG1sxlSlkZmzvxdw==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^18.0.0" + } + }, + "node_modules/@types/btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha512-wJsiX1tosQ+J5+bY5LrSahHxr2wT+uME5UDwdN1kg4frt40euqA+wzECkmq4t5QbveHiJepfdThgQrPw6KiSlg==", + "dev": true + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", + "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==", + "dev": true + }, "node_modules/array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true }, + "node_modules/btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==", + "dev": true + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true + }, "node_modules/compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", @@ -54,6 +263,12 @@ "node": ">=10" } }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -66,6 +281,15 @@ "node": ">=8" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -75,12 +299,102 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dev": true, + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lru-cache": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz", + "integrity": "sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -90,6 +404,121 @@ "node": ">=0.6.0", "teleport": ">=0.2.0" } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "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/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/universal-github-app-jwt": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.1.1.tgz", + "integrity": "sha512-G33RTLrIBMFmlDV4u4CBF7dh71eWwykck4XgaxaIVeZKOYZRAAxvcGMRFTUclVY6xoUPQvO4Ne5wKGxYm/Yy9w==", + "dev": true, + "dependencies": { + "@types/jsonwebtoken": "^9.0.0", + "jsonwebtoken": "^9.0.0" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/package.json b/package.json index e946eeb3..f76a7165 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,18 @@ { "name": "publish-java-package-with-maven-on-github-packages", "private": true, + "type": "module", "version": "1.0.0", "author": "Coveo", "description": "CI related stuff only", "license": "Apache-2.0", "devDependencies": { - "@commitlint/config-conventional": "17.4.4" + "@actions/core": "^1.10.0", + "@commitlint/config-conventional": "17.4.4", + "@octokit/auth-app": "^4.0.9" + }, + "scripts": { + "get-token": "node get-token.mjs" }, "commitlint": { "extends": [ diff --git a/pom.xml b/pom.xml index 9c4183c9..008ede3a 100644 --- a/pom.xml +++ b/pom.xml @@ -39,13 +39,10 @@ - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + github + GitHub Packages + ${github.packages.url} @@ -109,17 +106,6 @@ - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.6 - true - - ossrh - https://oss.sonatype.org/ - true - - org.apache.maven.plugins maven-gpg-plugin @@ -193,6 +179,7 @@ 11 11 UTF-8 + https://maven.pkg.github.com/coveo/push-api-client.java 2.37.0 \ No newline at end of file diff --git a/utils/get-token.mjs b/utils/get-token.mjs new file mode 100644 index 00000000..1660f6ad --- /dev/null +++ b/utils/get-token.mjs @@ -0,0 +1,18 @@ +import {createAppAuth} from '@octokit/auth-app'; +import {setSecret} from '@actions/core' + +const auth = createAppAuth({ + appId: process.env.RELEASER_APP_ID, + privateKey: process.env.RELEASER_PRIVATE_KEY, + clientId: process.env.RELEASER_CLIENT_ID, + clientSecret: process.env.RELEASER_CLIENT_SECRET, +}); + +// Retrieve installation access token +const {token} = await auth({ + type: 'installation', + installationId: process.env.RELEASER_INSTALLATION_ID, +}); + +setSecret(token); +exportVariable('RELEASE_TOKEN', token); \ No newline at end of file From 7e90aa479ab3a33337c8193305a5731501aa7a91 Mon Sep 17 00:00:00 2001 From: Yassine Date: Mon, 12 Jun 2023 14:55:34 -0400 Subject: [PATCH 20/44] ci: adjust script path (#49) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f76a7165..e5a2860b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@octokit/auth-app": "^4.0.9" }, "scripts": { - "get-token": "node get-token.mjs" + "get-token": "node utils/get-token.mjs" }, "commitlint": { "extends": [ From fea6a26228d0588f526c3cf1ab3cf58c01ff29f7 Mon Sep 17 00:00:00 2001 From: Yassine Date: Mon, 12 Jun 2023 15:00:34 -0400 Subject: [PATCH 21/44] ci: add missing environment variables (#50) * fix: adjust script path * ci: add missing env secrets --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f8e389a4..0d2221d0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,6 +22,12 @@ jobs: - name: Get Release Token run: npm run get-token + env: + RELEASER_APP_ID: ${{ secrets.RELEASER_APP_ID }} + RELEASER_PRIVATE_KEY: ${{ secrets.RELEASER_PRIVATE_KEY }} + RELEASER_CLIENT_ID: ${{ secrets.RELEASER_CLIENT_ID }} + RELEASER_CLIENT_SECRET: ${{ secrets.RELEASER_CLIENT_SECRET }} + RELEASER_INSTALLATION_ID: ${{ secrets.RELEASER_INSTALLATION_ID }} - uses: actions/setup-java@v3 name: Set up Java From 77cbdd1fb3e3c260db34131620024fdf41149227 Mon Sep 17 00:00:00 2001 From: Yassine Date: Mon, 12 Jun 2023 15:03:36 -0400 Subject: [PATCH 22/44] ci: add missing export (#51) * ci: add missing export --- utils/get-token.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/get-token.mjs b/utils/get-token.mjs index 1660f6ad..8e4b1286 100644 --- a/utils/get-token.mjs +++ b/utils/get-token.mjs @@ -1,5 +1,5 @@ import {createAppAuth} from '@octokit/auth-app'; -import {setSecret} from '@actions/core' +import {setSecret, exportVariable} from '@actions/core' const auth = createAppAuth({ appId: process.env.RELEASER_APP_ID, From 1feb9cc911ae691f28ccae96c8efecbf466e6e94 Mon Sep 17 00:00:00 2001 From: Houssein Dhayne <95109658+hdhayneCoveo@users.noreply.github.com> Date: Mon, 12 Jun 2023 16:23:40 -0400 Subject: [PATCH 23/44] docs: create sample code to stream document (#43) --- samples/StreamDocuments.java | 34 +++++++++++++++++++ .../coveo/pushapiclient/StreamService.java | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 samples/StreamDocuments.java diff --git a/samples/StreamDocuments.java b/samples/StreamDocuments.java new file mode 100644 index 00000000..38963c84 --- /dev/null +++ b/samples/StreamDocuments.java @@ -0,0 +1,34 @@ +import com.coveo.pushapiclient.*; +import com.coveo.pushapiclient.exceptions.NoOpenStreamException; + +import java.io.IOException; +import java.util.HashMap; + +public class StreamDocuments { + + public static void main(String[] args) throws IOException, InterruptedException, NoOpenStreamException { + + PlatformUrl platformUrl = new PlatformUrlBuilder().withEnvironment(Environment.PRODUCTION).withRegion(Region.US).build(); + CatalogSource catalogSource = CatalogSource.fromPlatformUrl("my_api_key","my_org_id","my_source_id", platformUrl); + + StreamService streamService = new StreamService(catalogSource); + + DocumentBuilder document1 = new DocumentBuilder("https://my.document.uri", "My document title") + .withData("these words will be searchable") + .withAuthor("bob") + .withClickableUri("https://my.document.click.com") + .withFileExtension(".html") + .withMetadata(new HashMap<>() {{ + put("tags", new String[]{"the_first_tag", "the_second_tag"}); + put("version", 1); + put("somekey", "somevalue"); + }}); + + streamService.add(document1); + + DocumentBuilder document2 = new DocumentBuilder("https://my.document2.uri", "My document2 title"); + streamService.add(document2); + + streamService.close(); + } +} diff --git a/src/main/java/com/coveo/pushapiclient/StreamService.java b/src/main/java/com/coveo/pushapiclient/StreamService.java index 51ec841b..b583f6ce 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamService.java +++ b/src/main/java/com/coveo/pushapiclient/StreamService.java @@ -62,7 +62,7 @@ public StreamService(StreamEnabledSource source) { * * *

- * For more code samples, visit Stream data to your catalog source + * For more code samples, @see `samples/StreamDocuments.java` * * @param document The documentBuilder to add to your source * @throws InterruptedException From d28fe2ebf12fc8f2071cabd22763e2397ab03919 Mon Sep 17 00:00:00 2001 From: Houssein Dhayne <95109658+hdhayneCoveo@users.noreply.github.com> Date: Mon, 12 Jun 2023 16:31:30 -0400 Subject: [PATCH 24/44] feat:expose publicly PushSource,CatalogSource,StreamService (#46) --- src/main/java/com/coveo/pushapiclient/CatalogSource.java | 3 +-- src/main/java/com/coveo/pushapiclient/PushSource.java | 3 +-- src/main/java/com/coveo/pushapiclient/StreamService.java | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/CatalogSource.java b/src/main/java/com/coveo/pushapiclient/CatalogSource.java index 27980c92..2bbb06eb 100644 --- a/src/main/java/com/coveo/pushapiclient/CatalogSource.java +++ b/src/main/java/com/coveo/pushapiclient/CatalogSource.java @@ -5,8 +5,7 @@ import java.net.URL; import java.net.http.HttpResponse; -// TODO: LENS-851 - Make public when ready -class CatalogSource implements StreamEnabledSource { +public class CatalogSource implements StreamEnabledSource { private final String apiKey; private final ApiUrl urlExtractor; diff --git a/src/main/java/com/coveo/pushapiclient/PushSource.java b/src/main/java/com/coveo/pushapiclient/PushSource.java index b45b2c30..8e2075c1 100644 --- a/src/main/java/com/coveo/pushapiclient/PushSource.java +++ b/src/main/java/com/coveo/pushapiclient/PushSource.java @@ -6,8 +6,7 @@ import java.net.URL; import java.net.http.HttpResponse; -// TODO: LENS-851 - Make public when ready -class PushSource implements PushEnabledSource { +public class PushSource implements PushEnabledSource { private final String apiKey; private final ApiUrl urlExtractor; private final PlatformClient platformClient; diff --git a/src/main/java/com/coveo/pushapiclient/StreamService.java b/src/main/java/com/coveo/pushapiclient/StreamService.java index b583f6ce..0213d720 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamService.java +++ b/src/main/java/com/coveo/pushapiclient/StreamService.java @@ -5,8 +5,7 @@ import java.io.IOException; import java.net.http.HttpResponse; -// TODO: LENS-851 - Make public -class StreamService { +public class StreamService { private final StreamEnabledSource source; private final PlatformClient platformClient; private StreamServiceInternal service; From 345664607bb3f99137d0acde48097cdb00ce52ef Mon Sep 17 00:00:00 2001 From: Yassine Date: Tue, 13 Jun 2023 09:55:31 -0400 Subject: [PATCH 25/44] ci: fix release script (#52) * ci: read value from context --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d2221d0..eb02863a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,4 +45,4 @@ jobs: package-name: release-please-action default-branch: main pull-request-title-pattern: 'chore${scope}: release${component} ${version} [skip-ci]' - token: $RELEASE_TOKEN + token: ${{ env.RELEASE_TOKEN }} From 52b35576551930c41e07aed2af2a9973c0ae8d9a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 12:48:10 -0400 Subject: [PATCH 26/44] ci: configure Renovate (#56) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- renovate.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..39a2b6e9 --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ] +} From 6f343d24e4245c7e2cd0eaf84ab500bb6f369b39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 12:50:45 -0400 Subject: [PATCH 27/44] chore(deps): update dependency junit:junit to v4.13.1 [security] (#58) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 008ede3a..be97d86b 100644 --- a/pom.xml +++ b/pom.xml @@ -156,7 +156,7 @@ junit junit - 4.12 + 4.13.1 test From 366323dcb1fe9e4e5eb1d083dd2b6774cacae9c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 16:53:03 +0000 Subject: [PATCH 28/44] fix(deps): update dependency com.google.code.gson:gson to v2.8.9 [security] (#57) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index be97d86b..f5fd5c9a 100644 --- a/pom.xml +++ b/pom.xml @@ -135,7 +135,7 @@ com.google.code.gson gson - 2.8.7 + 2.8.9 io.github.cdimascio From bb8d5fdc3f4017ff21593147d1280e85dc77f01e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 18:57:26 +0000 Subject: [PATCH 29/44] chore(deps): update actions/checkout digest to c85c95e (#60) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/pr-title-semantic-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-title-semantic-lint.yml b/.github/workflows/pr-title-semantic-lint.yml index 2f50d6ed..2ad95ccc 100644 --- a/.github/workflows/pr-title-semantic-lint.yml +++ b/.github/workflows/pr-title-semantic-lint.yml @@ -9,7 +9,7 @@ jobs: env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} steps: - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3 - name: Ensure PR Title is Semantic run: | npm ci From d89982f686e9c66035bc45e00cc160b11a151a9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:00:05 +0000 Subject: [PATCH 30/44] chore(deps): update dependency junit:junit to v4.13.2 (#61) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f5fd5c9a..8be00bb5 100644 --- a/pom.xml +++ b/pom.xml @@ -156,7 +156,7 @@ junit junit - 4.13.1 + 4.13.2 test From c8559aa88c2ee2ad8e41c3dadece61222e5f6952 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:26:03 -0400 Subject: [PATCH 31/44] chore(deps): update dependency @commitlint/config-conventional to v17.6.5 (#62) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d5612dd..6aa4c5eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Apache-2.0", "devDependencies": { "@actions/core": "^1.10.0", - "@commitlint/config-conventional": "17.4.4", + "@commitlint/config-conventional": "17.6.5", "@octokit/auth-app": "^4.0.9" } }, @@ -34,9 +34,9 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.4.4.tgz", - "integrity": "sha512-u6ztvxqzi6NuhrcEDR7a+z0yrh11elY66nRrQIpqsqW6sZmpxYkDLtpRH8jRML+mmxYQ8s4qqF06Q/IQx5aJeQ==", + "version": "17.6.5", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.6.5.tgz", + "integrity": "sha512-Xl9H9KLl86NZm5CYNTNF9dcz1xelE/EbvhWIWcYxG/rn3UWYWdWmmnX2q6ZduNdLFSGbOxzUpIx61j5zxbeXxg==", "dev": true, "dependencies": { "conventional-changelog-conventionalcommits": "^5.0.0" diff --git a/package.json b/package.json index e5a2860b..66a16391 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "license": "Apache-2.0", "devDependencies": { "@actions/core": "^1.10.0", - "@commitlint/config-conventional": "17.4.4", + "@commitlint/config-conventional": "17.6.5", "@octokit/auth-app": "^4.0.9" }, "scripts": { From 3ddf532ef91174bac283f0bf706f80b94b1b7d3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:28:47 +0000 Subject: [PATCH 32/44] chore(deps): update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.5.0 (#63) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8be00bb5..4acdaaf5 100644 --- a/pom.xml +++ b/pom.xml @@ -93,7 +93,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.3.0 + 3.5.0 all,-missing From 57dc72599db1457ab183edd70fade10e5192a499 Mon Sep 17 00:00:00 2001 From: Yassine Date: Tue, 13 Jun 2023 15:33:40 -0400 Subject: [PATCH 33/44] ci: fix release script (#54) * ci: use expression syntax --- .github/workflows/auto-approve-renovate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-approve-renovate.yml b/.github/workflows/auto-approve-renovate.yml index 1ef4f095..ce48a784 100644 --- a/.github/workflows/auto-approve-renovate.yml +++ b/.github/workflows/auto-approve-renovate.yml @@ -10,7 +10,7 @@ on: jobs: auto-approve: runs-on: ubuntu-latest - if: (github.actor == 'developer-experience-bot[bot]') && (contains(join(github.event.pull_request.labels.*.name), 'snpashot')) + if: "${{ (github.actor == 'developer-experience-bot[bot]') && contains(github.event.pull_request.labels.*.name, 'autorelease: snapshot') }}" steps: - name: auto-approve id: auto-approve From f757ac17d76879942ce2f6ab28f4785b8bde1835 Mon Sep 17 00:00:00 2001 From: "developer-experience-bot[bot]" <91079284+developer-experience-bot[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:46:06 +0000 Subject: [PATCH 34/44] chore(main): release 2.0.1-SNAPSHOT (#53) * chore(main): release 2.0.1-SNAPSHOT --------- Co-authored-by: developer-experience-bot[bot] <91079284+developer-experience-bot[bot]@users.noreply.github.com> --- pom.xml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 4acdaaf5..d04fee58 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 com.coveo push-api-client.java - 2.2.0 + 2.0.1-SNAPSHOT ${project.groupId}:${project.artifactId} jar Coveo Push API client. See more on https://github.com/coveo/push-api-client.java @@ -53,7 +51,7 @@ org.apache.maven.plugins maven-source-plugin 3.0.0 - + attach-sources @@ -76,7 +74,7 @@ src/test/java/**/*.java - + From 1609aca11ffd8476a5a070d783514445577c9979 Mon Sep 17 00:00:00 2001 From: "developer-experience-bot[bot]" <91079284+developer-experience-bot[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:49:09 -0400 Subject: [PATCH 35/44] chore(main): release 2.0.1-SNAPSHOT (#64) Co-authored-by: developer-experience-bot[bot] <91079284+developer-experience-bot[bot]@users.noreply.github.com> From 9631b80054c79b75291d53c9662c6c22ace52563 Mon Sep 17 00:00:00 2001 From: Yassine Date: Wed, 14 Jun 2023 10:51:57 -0400 Subject: [PATCH 36/44] ci: update renovate config (#55) https://coveord.atlassian.net/browse/LENS-924 --- renovate.json | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/renovate.json b/renovate.json index 39a2b6e9..55b110fe 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,22 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "enabled": true, "extends": [ - "config:base" - ] -} + ":semanticPrefixFixDepsChoreOthers", + "schedule:earlyMondays" + ], + "packageRules": [ + { + "matchPackagePatterns": [ + "*" + ], + "groupName": "all dependencies", + "groupSlug": "all" + } + ], + "rangeStrategy": "auto", + "lockFileMaintenance": { + "enabled": true + }, + "automerge": true, + "commitMessageSuffix": "J:CDX-227" +} \ No newline at end of file From 2989459be56bc5b15e0fed82e323523e86a89425 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Thu, 15 Jun 2023 13:10:45 -0400 Subject: [PATCH 37/44] feat: add logger on queue --- pom.xml | 5 +++++ .../coveo/pushapiclient/DocumentUploadQueue.java | 9 ++++++++- src/main/resources/log4j2.xml | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/log4j2.xml diff --git a/pom.xml b/pom.xml index d04fee58..60b84551 100644 --- a/pom.xml +++ b/pom.xml @@ -130,6 +130,11 @@ + + org.apache.logging.log4j + log4j-core + 2.20.0 + com.google.code.gson gson diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index bd83a2bc..3f61487f 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -1,10 +1,14 @@ package com.coveo.pushapiclient; import java.io.IOException; +import java.net.http.HttpResponse; import java.util.ArrayList; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** Represents a queue for uploading documents using a specified upload strategy */ class DocumentUploadQueue { + private static final Logger logger = LogManager.getLogger(DocumentUploadQueue.class); private final UploadStrategy uploader; private final int maxQueueSize = 5 * 1024 * 1024; private ArrayList documentToAddList; @@ -34,7 +38,8 @@ public void flush() throws IOException, InterruptedException { } BatchUpdate batch = this.getBatch(); // TODO: LENS-871: support concurrent requests - this.uploader.apply(batch); + HttpResponse response = this.uploader.apply(batch); + logger.debug("Sending document batch: ", response.statusCode(), response.body()); this.size = 0; this.documentToAddList.clear(); this.documentToDeleteList.clear(); @@ -58,6 +63,7 @@ public void add(DocumentBuilder document) throws IOException, InterruptedExcepti this.flush(); } documentToAddList.add(document); + logger.info("Adding document to batch: ", document.getDocument().uri); this.size += sizeOfDoc; } @@ -79,6 +85,7 @@ public void add(DeleteDocument document) throws IOException, InterruptedExceptio this.flush(); } documentToDeleteList.add(document); + logger.info("Adding document to batch: ", document.documentId); this.size += sizeOfDoc; } diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 00000000..4925e4e7 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + From 85344962ab3bb9e69b2ac056118b85d92456a2cd Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Tue, 20 Jun 2023 15:15:59 -0400 Subject: [PATCH 38/44] chore: fix merge conflict --- .../com/coveo/pushapiclient/DocumentUploadQueue.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index bd83a2bc..3f61487f 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -1,10 +1,14 @@ package com.coveo.pushapiclient; import java.io.IOException; +import java.net.http.HttpResponse; import java.util.ArrayList; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** Represents a queue for uploading documents using a specified upload strategy */ class DocumentUploadQueue { + private static final Logger logger = LogManager.getLogger(DocumentUploadQueue.class); private final UploadStrategy uploader; private final int maxQueueSize = 5 * 1024 * 1024; private ArrayList documentToAddList; @@ -34,7 +38,8 @@ public void flush() throws IOException, InterruptedException { } BatchUpdate batch = this.getBatch(); // TODO: LENS-871: support concurrent requests - this.uploader.apply(batch); + HttpResponse response = this.uploader.apply(batch); + logger.debug("Sending document batch: ", response.statusCode(), response.body()); this.size = 0; this.documentToAddList.clear(); this.documentToDeleteList.clear(); @@ -58,6 +63,7 @@ public void add(DocumentBuilder document) throws IOException, InterruptedExcepti this.flush(); } documentToAddList.add(document); + logger.info("Adding document to batch: ", document.getDocument().uri); this.size += sizeOfDoc; } @@ -79,6 +85,7 @@ public void add(DeleteDocument document) throws IOException, InterruptedExceptio this.flush(); } documentToDeleteList.add(document); + logger.info("Adding document to batch: ", document.documentId); this.size += sizeOfDoc; } From 3e88e228c53b5a0a848fbea6bd7e86cee1e00898 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Thu, 22 Jun 2023 16:05:05 -0400 Subject: [PATCH 39/44] feat: add logging --- .../java/com/coveo/pushapiclient/ApiCore.java | 45 +++++++++++++++++-- .../pushapiclient/DocumentUploadQueue.java | 19 +++++--- .../pushapiclient/StreamServiceInternal.java | 5 +++ src/main/resources/log4j2.xml | 13 ------ 4 files changed, 60 insertions(+), 22 deletions(-) delete mode 100644 src/main/resources/log4j2.xml diff --git a/src/main/java/com/coveo/pushapiclient/ApiCore.java b/src/main/java/com/coveo/pushapiclient/ApiCore.java index 5e07feb3..ce73e2c0 100644 --- a/src/main/java/com/coveo/pushapiclient/ApiCore.java +++ b/src/main/java/com/coveo/pushapiclient/ApiCore.java @@ -6,10 +6,13 @@ import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublisher; import java.net.http.HttpResponse; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; // TODO: LENS-934 - Support throttling class ApiCore { private final HttpClient httpClient; + private static final Logger logger = LogManager.getLogger(ApiCore.class); public ApiCore() { this.httpClient = HttpClient.newHttpClient(); @@ -26,26 +29,60 @@ public HttpResponse post(URI uri, String[] headers) public HttpResponse post(URI uri, String[] headers, BodyPublisher body) throws IOException, InterruptedException { + logger.debug("POST " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).POST(body).build(); - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + this.logResponse(response); + return response; } public HttpResponse put(URI uri, String[] headers, BodyPublisher body) throws IOException, InterruptedException { + logger.debug("PUT " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).PUT(body).build(); - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + this.logResponse(response); + return response; } public HttpResponse delete(URI uri, String[] headers) throws IOException, InterruptedException { + logger.debug("DELETE " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).DELETE().build(); - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + this.logResponse(response); + return response; } public HttpResponse delete(URI uri, String[] headers, BodyPublisher body) throws IOException, InterruptedException { + logger.debug("DELETE " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).method("DELETE", body).build(); - return this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + this.logResponse(response); + return response; + } + + private void logResponse(HttpResponse response) { + if (response == null) { + return; + } + int status = response.statusCode(); + String method = response.request().method(); + String statusMessage = method + " status: " + status; + String responseMessage = method + " response: " + response.body(); + + if (status < 200 || status >= 300) { + logger.error(statusMessage); + logger.error(responseMessage); + } else { + logger.debug(statusMessage); + logger.debug(responseMessage); + } } } diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index 3f61487f..0371e5e6 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -34,17 +34,26 @@ public DocumentUploadQueue(UploadStrategy uploader) { */ public void flush() throws IOException, InterruptedException { if (this.isEmpty()) { + logger.debug("Empty batch. Skipping upload"); return; } - BatchUpdate batch = this.getBatch(); // TODO: LENS-871: support concurrent requests - HttpResponse response = this.uploader.apply(batch); - logger.debug("Sending document batch: ", response.statusCode(), response.body()); + this.applyStrategy(); + this.size = 0; this.documentToAddList.clear(); this.documentToDeleteList.clear(); } + private void applyStrategy() throws IOException, InterruptedException { + BatchUpdate batch = this.getBatch(); + logger.info("Uploading document batch"); + HttpResponse response = this.uploader.apply(batch); + if (response != null && !response.body().isEmpty()) { + logger.info("Document batch upload response: " + response.body()); + } + } + /** * Adds a {@link DocumentBuilder} to the upload queue and flushes the queue if it exceeds the * maximum content length. See {@link DocumentUploadQueue#flush}. @@ -63,7 +72,7 @@ public void add(DocumentBuilder document) throws IOException, InterruptedExcepti this.flush(); } documentToAddList.add(document); - logger.info("Adding document to batch: ", document.getDocument().uri); + logger.info("Adding document to batch: " + document.getDocument().uri); this.size += sizeOfDoc; } @@ -85,7 +94,7 @@ public void add(DeleteDocument document) throws IOException, InterruptedExceptio this.flush(); } documentToDeleteList.add(document); - logger.info("Adding document to batch: ", document.documentId); + logger.info("Adding document to batch: " + document.documentId); this.size += sizeOfDoc; } diff --git a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java index e5579752..d678386a 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java +++ b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java @@ -4,9 +4,12 @@ import com.google.gson.Gson; import java.io.IOException; import java.net.http.HttpResponse; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** For internal use only. Made to easily test the service without having to use PowerMock */ class StreamServiceInternal { + private static final Logger logger = LogManager.getLogger(StreamServiceInternal.class); private final StreamEnabledSource source; private final PlatformClient platformClient; private String streamId; @@ -35,10 +38,12 @@ public HttpResponse close() } queue.flush(); String sourceId = this.getSourceId(); + logger.info("Closing open stream " + this.streamId); return this.platformClient.closeStream(sourceId, this.streamId); } private String getStreamId() throws IOException, InterruptedException { + logger.info("Opening new stream"); String sourceId = this.getSourceId(); HttpResponse response = this.platformClient.openStream(sourceId); StreamResponse streamResponse = new Gson().fromJson(response.body(), StreamResponse.class); diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml deleted file mode 100644 index 4925e4e7..00000000 --- a/src/main/resources/log4j2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - From 161e45b957c6583289649fa47833c6a7b12b41f6 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Thu, 22 Jun 2023 16:21:47 -0400 Subject: [PATCH 40/44] remove extra log --- .../coveo/pushapiclient/DocumentUploadQueue.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index 0371e5e6..979654a7 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -38,22 +38,15 @@ public void flush() throws IOException, InterruptedException { return; } // TODO: LENS-871: support concurrent requests - this.applyStrategy(); + BatchUpdate batch = this.getBatch(); + logger.info("Uploading document batch"); + this.uploader.apply(batch); this.size = 0; this.documentToAddList.clear(); this.documentToDeleteList.clear(); } - private void applyStrategy() throws IOException, InterruptedException { - BatchUpdate batch = this.getBatch(); - logger.info("Uploading document batch"); - HttpResponse response = this.uploader.apply(batch); - if (response != null && !response.body().isEmpty()) { - logger.info("Document batch upload response: " + response.body()); - } - } - /** * Adds a {@link DocumentBuilder} to the upload queue and flushes the queue if it exceeds the * maximum content length. See {@link DocumentUploadQueue#flush}. From 95795504349658d1b780c6690d992e785dbe66f8 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Mon, 26 Jun 2023 09:33:30 -0400 Subject: [PATCH 41/44] add logger to APICore --- .../java/com/coveo/pushapiclient/ApiCore.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/ApiCore.java b/src/main/java/com/coveo/pushapiclient/ApiCore.java index ce73e2c0..50f575f6 100644 --- a/src/main/java/com/coveo/pushapiclient/ApiCore.java +++ b/src/main/java/com/coveo/pushapiclient/ApiCore.java @@ -12,14 +12,16 @@ // TODO: LENS-934 - Support throttling class ApiCore { private final HttpClient httpClient; - private static final Logger logger = LogManager.getLogger(ApiCore.class); + private final Logger logger; public ApiCore() { this.httpClient = HttpClient.newHttpClient(); + this.logger = LogManager.getLogger(ApiCore.class); } - public ApiCore(HttpClient httpClient) { + public ApiCore(HttpClient httpClient, Logger logger) { this.httpClient = httpClient; + this.logger = logger; } public HttpResponse post(URI uri, String[] headers) @@ -29,7 +31,7 @@ public HttpResponse post(URI uri, String[] headers) public HttpResponse post(URI uri, String[] headers, BodyPublisher body) throws IOException, InterruptedException { - logger.debug("POST " + uri); + this.logger.debug("POST " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).POST(body).build(); HttpResponse response = this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); @@ -39,7 +41,7 @@ public HttpResponse post(URI uri, String[] headers, BodyPublisher body) public HttpResponse put(URI uri, String[] headers, BodyPublisher body) throws IOException, InterruptedException { - logger.debug("PUT " + uri); + this.logger.debug("PUT " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).PUT(body).build(); HttpResponse response = this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); @@ -49,7 +51,7 @@ public HttpResponse put(URI uri, String[] headers, BodyPublisher body) public HttpResponse delete(URI uri, String[] headers) throws IOException, InterruptedException { - logger.debug("DELETE " + uri); + this.logger.debug("DELETE " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).DELETE().build(); HttpResponse response = this.httpClient.send(request, HttpResponse.BodyHandlers.ofString()); @@ -59,7 +61,7 @@ public HttpResponse delete(URI uri, String[] headers) public HttpResponse delete(URI uri, String[] headers, BodyPublisher body) throws IOException, InterruptedException { - logger.debug("DELETE " + uri); + this.logger.debug("DELETE " + uri); HttpRequest request = HttpRequest.newBuilder().headers(headers).uri(uri).method("DELETE", body).build(); HttpResponse response = @@ -78,11 +80,11 @@ private void logResponse(HttpResponse response) { String responseMessage = method + " response: " + response.body(); if (status < 200 || status >= 300) { - logger.error(statusMessage); - logger.error(responseMessage); + this.logger.error(statusMessage); + this.logger.error(responseMessage); } else { - logger.debug(statusMessage); - logger.debug(responseMessage); + this.logger.debug(statusMessage); + this.logger.debug(responseMessage); } } } From ed64512b5d35b166a7a37b59889ee159583d6306 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Mon, 26 Jun 2023 11:40:47 -0400 Subject: [PATCH 42/44] add unit tests --- README.md | 25 ++++++ .../pushapiclient/DocumentUploadQueue.java | 1 - .../coveo/pushapiclient/PlatformClient.java | 3 +- .../coveo/pushapiclient/StreamService.java | 6 +- .../pushapiclient/StreamServiceInternal.java | 16 ++-- .../com/coveo/pushapiclient/ApiCoreTest.java | 82 +++++++++++++++++++ .../StreamServiceInternalTest.java | 14 ++++ 7 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 src/test/java/com/coveo/pushapiclient/ApiCoreTest.java diff --git a/README.md b/README.md index 13ebbee0..6412a8ac 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,31 @@ public class PushOneDocument { ``` +## Logging +When pushing multiple documents into your source using a service (e.g. `PushService`, `StreamService`), make sure to configure a **logger** to be able to see what happens. +to do so .. in your `resources` folder. + +### Log4j2 XML Configuration Example +To log execution output into the console, use the below `log4j2.xml` configuration: +```xml + + + + + + + + + + + + + + +``` + +See [Log4j2 configuration](https://logging.apache.org/log4j/2.x/manual/configuration.html) for more details. + ## Local Setup to Contribute ### Formatting diff --git a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java index 979654a7..5e81f55f 100644 --- a/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java +++ b/src/main/java/com/coveo/pushapiclient/DocumentUploadQueue.java @@ -1,7 +1,6 @@ package com.coveo.pushapiclient; import java.io.IOException; -import java.net.http.HttpResponse; import java.util.ArrayList; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/com/coveo/pushapiclient/PlatformClient.java b/src/main/java/com/coveo/pushapiclient/PlatformClient.java index e97fe9ff..f66409e4 100644 --- a/src/main/java/com/coveo/pushapiclient/PlatformClient.java +++ b/src/main/java/com/coveo/pushapiclient/PlatformClient.java @@ -10,6 +10,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.stream.Stream; +import org.apache.logging.log4j.LogManager; /** PlatformClient handles network requests to the Coveo platform */ public class PlatformClient { @@ -58,7 +59,7 @@ public PlatformClient(String apiKey, String organizationId, PlatformUrl platform public PlatformClient(String apiKey, String organizationId, HttpClient httpClient) { this.apiKey = apiKey; this.organizationId = organizationId; - this.api = new ApiCore(httpClient); + this.api = new ApiCore(httpClient, LogManager.getLogger(ApiCore.class)); this.platformUrl = new PlatformUrlBuilder().build(); } diff --git a/src/main/java/com/coveo/pushapiclient/StreamService.java b/src/main/java/com/coveo/pushapiclient/StreamService.java index 0213d720..3ba94f5e 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamService.java +++ b/src/main/java/com/coveo/pushapiclient/StreamService.java @@ -4,6 +4,8 @@ import com.google.gson.Gson; import java.io.IOException; import java.net.http.HttpResponse; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class StreamService { private final StreamEnabledSource source; @@ -27,11 +29,13 @@ public StreamService(StreamEnabledSource source) { String organizationId = source.getOrganizationId(); PlatformUrl platformUrl = source.getPlatformUrl(); UploadStrategy uploader = this.getUploadStrategy(); + Logger logger = LogManager.getLogger(StreamService.class); this.source = source; this.queue = new DocumentUploadQueue(uploader); this.platformClient = new PlatformClient(apiKey, organizationId, platformUrl); - this.service = new StreamServiceInternal(this.source, this.queue, this.platformClient); + + this.service = new StreamServiceInternal(this.source, this.queue, this.platformClient, logger); } /** diff --git a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java index d678386a..e8364a09 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java +++ b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java @@ -4,22 +4,25 @@ import com.google.gson.Gson; import java.io.IOException; import java.net.http.HttpResponse; -import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** For internal use only. Made to easily test the service without having to use PowerMock */ class StreamServiceInternal { - private static final Logger logger = LogManager.getLogger(StreamServiceInternal.class); + private Logger logger; private final StreamEnabledSource source; private final PlatformClient platformClient; private String streamId; private DocumentUploadQueue queue; public StreamServiceInternal( - StreamEnabledSource source, DocumentUploadQueue queue, PlatformClient platformClient) { + StreamEnabledSource source, + DocumentUploadQueue queue, + PlatformClient platformClient, + Logger logger) { this.source = source; this.queue = queue; this.platformClient = platformClient; + this.logger = logger; } public String add(DocumentBuilder document) throws IOException, InterruptedException { @@ -34,16 +37,17 @@ public HttpResponse close() throws IOException, InterruptedException, NoOpenStreamException { if (this.streamId == null) { throw new NoOpenStreamException( - "No open stream detected. A stream will automatically be opened once you start adding documents."); + "No open stream detected. A stream will automatically be opened once you start adding" + + " documents."); } queue.flush(); String sourceId = this.getSourceId(); - logger.info("Closing open stream " + this.streamId); + this.logger.info("Closing open stream " + this.streamId); return this.platformClient.closeStream(sourceId, this.streamId); } private String getStreamId() throws IOException, InterruptedException { - logger.info("Opening new stream"); + this.logger.info("Opening new stream"); String sourceId = this.getSourceId(); HttpResponse response = this.platformClient.openStream(sourceId); StreamResponse streamResponse = new Gson().fromJson(response.body(), StreamResponse.class); diff --git a/src/test/java/com/coveo/pushapiclient/ApiCoreTest.java b/src/test/java/com/coveo/pushapiclient/ApiCoreTest.java new file mode 100644 index 00000000..c876fbfe --- /dev/null +++ b/src/test/java/com/coveo/pushapiclient/ApiCoreTest.java @@ -0,0 +1,82 @@ +package com.coveo.pushapiclient; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandler; +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class ApiCoreTest { + + @Mock private HttpClient httpClient; + @Mock private HttpRequest httpRequest; + @Mock private Logger logger; + @Mock private HttpResponse httpResponse; + + @InjectMocks private ApiCore api; + + private AutoCloseable closeable; + private static final String[] headers = { + "Content-Type", "application/json", "Accept", "application/json" + }; + + private void mockSuccessResponse() { + when(httpResponse.statusCode()).thenReturn(200); + when(httpResponse.body()).thenReturn("All good!"); + when(httpRequest.method()).thenReturn("POST"); + } + + private void mockErrorResponse() { + when(httpResponse.statusCode()).thenReturn(412); + when(httpResponse.body()).thenReturn("BAD_REQUEST"); + when(httpRequest.method()).thenReturn("DELETE"); + } + + @Before + public void setUp() throws Exception { + closeable = MockitoAnnotations.openMocks(this); + + when(httpClient.send(any(HttpRequest.class), any(BodyHandler.class))).thenReturn(httpResponse); + when(httpResponse.request()).thenReturn(httpRequest); + } + + @After + public void closeService() throws Exception { + closeable.close(); + } + + @Test + public void testShouldLogRequestAndResonse() + throws IOException, InterruptedException, URISyntaxException { + this.mockSuccessResponse(); + this.api.post(new URI("https://perdu.com/"), headers); + + verify(logger, times(1)).debug("POST https://perdu.com/"); + verify(logger, times(1)).debug("POST status: 200"); + verify(logger, times(1)).debug("POST response: All good!"); + } + + @Test + public void testShouldLogResponse() throws IOException, InterruptedException, URISyntaxException { + this.mockErrorResponse(); + this.api.delete(new URI("https://perdu.com/"), headers); + + verify(logger, times(1)).debug("DELETE https://perdu.com/"); + verify(logger, times(1)).error("DELETE status: 412"); + verify(logger, times(1)).error("DELETE response: BAD_REQUEST"); + } +} diff --git a/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java b/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java index d850c5e3..4acd9cec 100644 --- a/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java +++ b/src/test/java/com/coveo/pushapiclient/StreamServiceInternalTest.java @@ -1,5 +1,6 @@ package com.coveo.pushapiclient; +import static org.mockito.ArgumentMatchers.contains; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -7,6 +8,7 @@ import com.coveo.pushapiclient.exceptions.NoOpenStreamException; import java.io.IOException; import java.net.http.HttpResponse; +import org.apache.logging.log4j.core.Logger; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -21,6 +23,8 @@ public class StreamServiceInternalTest { @Mock private PlatformClient platformClient; + @Mock private Logger logger; + @InjectMocks private StreamServiceInternal service; @Mock private HttpResponse httpResponse; @@ -86,4 +90,14 @@ public void givenNoOpenStream_whenClose_thenShouldThrow() throws IOException, InterruptedException, NoOpenStreamException { service.close(); } + + @Test + public void testShouldLogInfo() throws IOException, InterruptedException, NoOpenStreamException { + service.add(documentA); + service.add(documentB); + verify(logger, times(1)).info("Opening new stream"); + + service.close(); + verify(logger, times(1)).info(contains("Closing open stream")); + } } From b9a8f91e0a6a4d0f001c6eeb60dc0db41131c590 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Mon, 26 Jun 2023 11:42:53 -0400 Subject: [PATCH 43/44] remove unecessary changes --- src/main/java/com/coveo/pushapiclient/PlatformClient.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/coveo/pushapiclient/PlatformClient.java b/src/main/java/com/coveo/pushapiclient/PlatformClient.java index f66409e4..a70bbb06 100644 --- a/src/main/java/com/coveo/pushapiclient/PlatformClient.java +++ b/src/main/java/com/coveo/pushapiclient/PlatformClient.java @@ -215,6 +215,7 @@ public HttpResponse deleteOldSecurityIdentities( throws IOException, InterruptedException { String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create( this.getBaseProviderURL(securityProviderId) @@ -253,6 +254,7 @@ public HttpResponse manageSecurityIdentities( throws IOException, InterruptedException { String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create( this.getBaseProviderURL(securityProviderId) @@ -280,6 +282,7 @@ public HttpResponse pushDocument( throws IOException, InterruptedException { String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create( this.getBasePushURL() @@ -307,6 +310,7 @@ public HttpResponse deleteDocument( throws IOException, InterruptedException { String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create( this.getBasePushURL() @@ -343,6 +347,7 @@ public HttpResponse requireStreamChunk(String sourceId, String streamId) throws IOException, InterruptedException { String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create( this.getBasePushURL() @@ -381,6 +386,7 @@ public HttpResponse updateSourceStatus(String sourceId, PushAPIStatus st throws IOException, InterruptedException { String[] headers = this.getHeaders(this.getAuthorizationHeader(), this.getContentTypeApplicationJSONHeader()); + URI uri = URI.create( this.getBasePushURL() From a656d38491487104b0524128b1a4704c328f1425 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Mon, 26 Jun 2023 13:01:29 -0400 Subject: [PATCH 44/44] revert formatting --- .../java/com/coveo/pushapiclient/StreamServiceInternal.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java index e8364a09..04b7bf1f 100644 --- a/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java +++ b/src/main/java/com/coveo/pushapiclient/StreamServiceInternal.java @@ -37,8 +37,7 @@ public HttpResponse close() throws IOException, InterruptedException, NoOpenStreamException { if (this.streamId == null) { throw new NoOpenStreamException( - "No open stream detected. A stream will automatically be opened once you start adding" - + " documents."); + "No open stream detected. A stream will automatically be opened once you start adding documents."); } queue.flush(); String sourceId = this.getSourceId();