From e0296ef852acb6117263c430b17f7b91d4547e03 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Fri, 19 May 2023 11:22:04 -0400 Subject: [PATCH 1/4] create `PushSource` and `catalogSource` classes --- .../java/com/coveo/pushapiclient/ApiUrl.java | 106 +++++++ .../com/coveo/pushapiclient/BaseSource.java | 18 ++ .../coveo/pushapiclient/CatalogSource.java | 143 +++++++++ .../pushapiclient/PushEnabledSource.java | 6 + .../com/coveo/pushapiclient/PushSource.java | 300 ++++++++++++++++++ .../java/com/coveo/pushapiclient/Source.java | 1 + .../pushapiclient/StreamEnabledSource.java | 6 + .../com/coveo/pushapiclient/ApiUrlTest.java | 94 ++++++ 8 files changed, 674 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..508e2c7c --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/ApiUrl.java @@ -0,0 +1,106 @@ +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 Push API URL + * + * @See https://docs.coveo.com/en/1546#push-api-url + */ +class ApiUrl { + private final String organizationId; + private final String sourceId; + private final PlatformUrl platformUrl; + + public ApiUrl(URL sourceUrl) throws MalformedURLException { + List identifiers = this.extractIdentifiers(sourceUrl); + this.organizationId = identifiers.get(0); + this.sourceId = identifiers.get(1); + this.platformUrl = this.extractPlatformUrl(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/([^/]+)", Pattern.CASE_INSENSITIVE); + 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", Pattern.CASE_INSENSITIVE); + 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..26450a9a --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/BaseSource.java @@ -0,0 +1,18 @@ +package com.coveo.pushapiclient; + +public interface BaseSource { + /** + * Return an instance of {@link PlatformClient} + * + * @return + */ + PlatformClient getPlatformClient(); + + /** + * Returns the unique identifier of the 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..2c4a2c71 --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/CatalogSource.java @@ -0,0 +1,143 @@ +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 PlatformClient platformClient; + private final String sourceId; + + /** + * 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 { + ApiUrl parser = new ApiUrl(sourceUrl); + PlatformUrl platformUrl = parser.getPlatformUrl(); + String organizationId = parser.getOrganizationId(); + this.sourceId = parser.getSourceId(); + this.platformClient = new PlatformClient(apiKey, organizationId, + 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 CatalogSource(String apiKey, String organizationId, String sourceId) { + PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); + this.sourceId = sourceId; + this.platformClient = new PlatformClient(apiKey, organizationId, + 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. + * + */ + public CatalogSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + this.sourceId = sourceId; + this.platformClient = new PlatformClient(apiKey, organizationId, + platformUrl); + } + + @Override + public String getId() { + return this.sourceId; + } + + @Override + public PlatformClient getPlatformClient() { + return this.platformClient; + } + +} 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..92c777bf --- /dev/null +++ b/src/main/java/com/coveo/pushapiclient/PushSource.java @@ -0,0 +1,300 @@ +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 PlatformClient platformClient; + private final String sourceId; + + @Override + public PlatformClient getPlatformClient() { + return this.platformClient; + } + + @Override + public String getId() { + return this.sourceId; + } + + /** + * 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 { + ApiUrl parser = new ApiUrl(sourceUrl); + PlatformUrl platformUrl = parser.getPlatformUrl(); + String organizationId = parser.getOrganizationId(); + this.sourceId = parser.getSourceId(); + this.platformClient = new PlatformClient(apiKey, organizationId, + platformUrl); + } + + /** + * Create a Push 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 Push source. + *

+ * The Source Id can be retrieved when you edit your + * source in the Coveo + * Administration Console + * + */ + public PushSource(String apiKey, String organizationId, String sourceId) { + PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); + this.sourceId = sourceId; + this.platformClient = new PlatformClient(apiKey, organizationId, + platformUrl); + } + + /** + * Create a Push 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 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. + * + */ + public PushSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { + this.sourceId = sourceId; + 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.sourceId, 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.sourceId, 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.sourceId, 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..1cdda355 --- /dev/null +++ b/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java @@ -0,0 +1,94 @@ +package com.coveo.pushapiclient; + +import static org.junit.Assert.assertEquals; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.junit.Before; +import org.junit.Test; + +public class ApiUrlTest { + + private ApiUrl defaultUrl; + private ApiUrl regionOnlyUrl; + private ApiUrl regionOnlyUrlCaseInsensitive; + private ApiUrl environmentOnlyUrl; + private ApiUrl environmentAndRegionUrl; + private ApiUrl streamURL; + + @Before + public void setUp() throws MalformedURLException { + defaultUrl = new ApiUrl( + new URL("https://api.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + regionOnlyUrl = new ApiUrl( + new URL("https://api-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + regionOnlyUrlCaseInsensitive = new ApiUrl( + new URL("https://api-EU.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + environmentOnlyUrl = new ApiUrl( + new URL("https://apidev.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + environmentAndRegionUrl = new ApiUrl( + new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + streamURL = new ApiUrl( + new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/stream/open")); + + } + + @Test + public void testSourceId() { + assertEquals(defaultUrl.getSourceId(), "my-source-id"); + assertEquals(regionOnlyUrl.getSourceId(), "my-source-id"); + assertEquals(regionOnlyUrlCaseInsensitive.getSourceId(), "my-source-id"); + assertEquals(environmentOnlyUrl.getSourceId(), "my-source-id"); + assertEquals(environmentAndRegionUrl.getSourceId(), "my-source-id"); + assertEquals(streamURL.getSourceId(), "my-source-id"); + } + + @Test + public void testOrganizationId() { + assertEquals(defaultUrl.getOrganizationId(), "my-org-id"); + assertEquals(regionOnlyUrl.getOrganizationId(), "my-org-id"); + assertEquals(regionOnlyUrlCaseInsensitive.getOrganizationId(), "my-org-id"); + assertEquals(environmentOnlyUrl.getOrganizationId(), "my-org-id"); + assertEquals(environmentAndRegionUrl.getOrganizationId(), "my-org-id"); + assertEquals(streamURL.getOrganizationId(), "my-org-id"); + } + + @Test + public void testPlatformUrl() { + assertEquals(defaultUrl.getPlatformUrl().getApiUrl(), "https://api.cloud.coveo.com"); + assertEquals(regionOnlyUrl.getPlatformUrl().getApiUrl(), "https://api-au.cloud.coveo.com"); + assertEquals(regionOnlyUrlCaseInsensitive.getPlatformUrl().getApiUrl(), "https://api-eu.cloud.coveo.com"); + assertEquals(environmentOnlyUrl.getPlatformUrl().getApiUrl(), "https://apidev.cloud.coveo.com"); + assertEquals(environmentAndRegionUrl.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); + assertEquals(streamURL.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); + } + + @Test(expected = MalformedURLException.class) + public void testInvalidEnvironementUrl() throws MalformedURLException { + defaultUrl = 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 { + 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 { + defaultUrl = 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 { + defaultUrl = new ApiUrl( + new URL("https://platform.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + + } +} From 5ef67724a2ec227b7137fa64c69fddb69e468aa1 Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Tue, 23 May 2023 10:24:38 -0400 Subject: [PATCH 2/4] apply ApiUrl corrections --- .../java/com/coveo/pushapiclient/ApiUrl.java | 7 +- .../com/coveo/pushapiclient/ApiUrlTest.java | 87 +++++++++---------- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/ApiUrl.java b/src/main/java/com/coveo/pushapiclient/ApiUrl.java index 508e2c7c..be761eb5 100644 --- a/src/main/java/com/coveo/pushapiclient/ApiUrl.java +++ b/src/main/java/com/coveo/pushapiclient/ApiUrl.java @@ -9,9 +9,10 @@ import java.util.regex.Pattern; /** - * Private util class to extract dynamic parts from a Push API URL + * Private util class to extract dynamic parts from a API 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; @@ -39,7 +40,7 @@ public PlatformUrl getPlatformUrl() { private List extractIdentifiers(URL sourceUrl) throws MalformedURLException { String host = sourceUrl.getPath(); - Pattern pattern = Pattern.compile("/push/v1/organizations/([^/]+)/sources/([^/]+)", Pattern.CASE_INSENSITIVE); + Pattern pattern = Pattern.compile("/push/v1/organizations/([^/]+)/sources/([^/]+)"); Matcher matcher = pattern.matcher(host); if (matcher.find()) { @@ -55,7 +56,7 @@ private List extractIdentifiers(URL sourceUrl) throws MalformedURLExcept private PlatformUrl extractPlatformUrl(URL sourceUrl) throws MalformedURLException { String host = sourceUrl.getHost(); - Pattern pattern = Pattern.compile("api([a-z]*)([a-z-]*)\\.cloud\\.coveo\\.com", Pattern.CASE_INSENSITIVE); + Pattern pattern = Pattern.compile("api([a-z]*)([a-z-]*)\\.cloud\\.coveo\\.com"); Matcher matcher = pattern.matcher(host); if (matcher.find()) { diff --git a/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java b/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java index 1cdda355..964dcb55 100644 --- a/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java +++ b/src/test/java/com/coveo/pushapiclient/ApiUrlTest.java @@ -5,89 +5,82 @@ import java.net.MalformedURLException; import java.net.URL; -import org.junit.Before; import org.junit.Test; public class ApiUrlTest { - private ApiUrl defaultUrl; - private ApiUrl regionOnlyUrl; - private ApiUrl regionOnlyUrlCaseInsensitive; - private ApiUrl environmentOnlyUrl; - private ApiUrl environmentAndRegionUrl; - private ApiUrl streamURL; - - @Before - public void setUp() throws MalformedURLException { - defaultUrl = new ApiUrl( + @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")); - regionOnlyUrl = new ApiUrl( - new URL("https://api-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - regionOnlyUrlCaseInsensitive = new ApiUrl( - new URL("https://api-EU.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - environmentOnlyUrl = new ApiUrl( - new URL("https://apidev.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - environmentAndRegionUrl = new ApiUrl( - new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); - streamURL = new ApiUrl( - new URL("https://apidev-au.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/stream/open")); - + assertEquals(url.getSourceId(), "my-source-id"); } @Test - public void testSourceId() { - assertEquals(defaultUrl.getSourceId(), "my-source-id"); - assertEquals(regionOnlyUrl.getSourceId(), "my-source-id"); - assertEquals(regionOnlyUrlCaseInsensitive.getSourceId(), "my-source-id"); - assertEquals(environmentOnlyUrl.getSourceId(), "my-source-id"); - assertEquals(environmentAndRegionUrl.getSourceId(), "my-source-id"); - assertEquals(streamURL.getSourceId(), "my-source-id"); + 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 testOrganizationId() { - assertEquals(defaultUrl.getOrganizationId(), "my-org-id"); - assertEquals(regionOnlyUrl.getOrganizationId(), "my-org-id"); - assertEquals(regionOnlyUrlCaseInsensitive.getOrganizationId(), "my-org-id"); - assertEquals(environmentOnlyUrl.getOrganizationId(), "my-org-id"); - assertEquals(environmentAndRegionUrl.getOrganizationId(), "my-org-id"); - assertEquals(streamURL.getOrganizationId(), "my-org-id"); - } + 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")); - @Test - public void testPlatformUrl() { assertEquals(defaultUrl.getPlatformUrl().getApiUrl(), "https://api.cloud.coveo.com"); assertEquals(regionOnlyUrl.getPlatformUrl().getApiUrl(), "https://api-au.cloud.coveo.com"); - assertEquals(regionOnlyUrlCaseInsensitive.getPlatformUrl().getApiUrl(), "https://api-eu.cloud.coveo.com"); assertEquals(environmentOnlyUrl.getPlatformUrl().getApiUrl(), "https://apidev.cloud.coveo.com"); assertEquals(environmentAndRegionUrl.getPlatformUrl().getApiUrl(), "https://apidev-au.cloud.coveo.com"); - assertEquals(streamURL.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 testInvalidEnvironementUrl() throws MalformedURLException { - defaultUrl = new ApiUrl( + 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 { - defaultUrl = new ApiUrl( - new URL("https://api-bar.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); + 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 { - defaultUrl = new ApiUrl( + 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 { - defaultUrl = new ApiUrl( + new ApiUrl( new URL("https://platform.cloud.coveo.com/push/v1/organizations/my-org-id/sources/my-source-id/documents")); } From 5da089231dc152c124e5cbc6caba2ecc55d4fa1a Mon Sep 17 00:00:00 2001 From: Yassine Date: Tue, 23 May 2023 11:41:11 -0400 Subject: [PATCH 3/4] Update src/main/java/com/coveo/pushapiclient/ApiUrl.java Co-authored-by: Benjamin Taillon <54454747+btaillon@users.noreply.github.com> --- src/main/java/com/coveo/pushapiclient/ApiUrl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/ApiUrl.java b/src/main/java/com/coveo/pushapiclient/ApiUrl.java index be761eb5..782bb8fa 100644 --- a/src/main/java/com/coveo/pushapiclient/ApiUrl.java +++ b/src/main/java/com/coveo/pushapiclient/ApiUrl.java @@ -39,9 +39,9 @@ public PlatformUrl getPlatformUrl() { } private List extractIdentifiers(URL sourceUrl) throws MalformedURLException { - String host = sourceUrl.getPath(); + String path = sourceUrl.getPath(); Pattern pattern = Pattern.compile("/push/v1/organizations/([^/]+)/sources/([^/]+)"); - Matcher matcher = pattern.matcher(host); + Matcher matcher = pattern.matcher(path); if (matcher.find()) { String organizationId = matcher.group(1); From c91d475d99a7783215995f0e3de796d28e94764c Mon Sep 17 00:00:00 2001 From: ylakhdar Date: Wed, 24 May 2023 15:18:41 -0400 Subject: [PATCH 4/4] add new getter to source classes --- .../java/com/coveo/pushapiclient/ApiUrl.java | 19 +++++- .../com/coveo/pushapiclient/BaseSource.java | 20 +++++- .../coveo/pushapiclient/CatalogSource.java | 51 ++++++++------ .../com/coveo/pushapiclient/PushSource.java | 66 +++++++++++-------- 4 files changed, 105 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/coveo/pushapiclient/ApiUrl.java b/src/main/java/com/coveo/pushapiclient/ApiUrl.java index 782bb8fa..b416576d 100644 --- a/src/main/java/com/coveo/pushapiclient/ApiUrl.java +++ b/src/main/java/com/coveo/pushapiclient/ApiUrl.java @@ -10,6 +10,7 @@ /** * 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 @@ -18,14 +19,28 @@ 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; } @@ -39,9 +54,9 @@ public PlatformUrl getPlatformUrl() { } private List extractIdentifiers(URL sourceUrl) throws MalformedURLException { - String path = sourceUrl.getPath(); + String host = sourceUrl.getPath(); Pattern pattern = Pattern.compile("/push/v1/organizations/([^/]+)/sources/([^/]+)"); - Matcher matcher = pattern.matcher(path); + Matcher matcher = pattern.matcher(host); if (matcher.find()) { String organizationId = matcher.group(1); diff --git a/src/main/java/com/coveo/pushapiclient/BaseSource.java b/src/main/java/com/coveo/pushapiclient/BaseSource.java index 26450a9a..a3edd80c 100644 --- a/src/main/java/com/coveo/pushapiclient/BaseSource.java +++ b/src/main/java/com/coveo/pushapiclient/BaseSource.java @@ -2,14 +2,28 @@ public interface BaseSource { /** - * Return an instance of {@link PlatformClient} + * Returns the API key used for all operations regarding your source. * * @return */ - PlatformClient getPlatformClient(); + String getApiKey(); /** - * Returns the unique identifier of the source + * 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 */ diff --git a/src/main/java/com/coveo/pushapiclient/CatalogSource.java b/src/main/java/com/coveo/pushapiclient/CatalogSource.java index 2c4a2c71..7fc9b08a 100644 --- a/src/main/java/com/coveo/pushapiclient/CatalogSource.java +++ b/src/main/java/com/coveo/pushapiclient/CatalogSource.java @@ -5,8 +5,8 @@ // TODO: LENS-851 - Make public when ready class CatalogSource implements StreamEnabledSource { - private final PlatformClient platformClient; - private final String sourceId; + private final String apiKey; + private final ApiUrl urlExtractor; /** * Create a Catalog source instance from its @@ -41,12 +41,8 @@ class CatalogSource implements StreamEnabledSource { * @throws MalformedURLException */ public CatalogSource(String apiKey, URL sourceUrl) throws MalformedURLException { - ApiUrl parser = new ApiUrl(sourceUrl); - PlatformUrl platformUrl = parser.getPlatformUrl(); - String organizationId = parser.getOrganizationId(); - this.sourceId = parser.getSourceId(); - this.platformClient = new PlatformClient(apiKey, organizationId, - platformUrl); + this.apiKey = apiKey; + this.urlExtractor = new ApiUrl(sourceUrl); } /** @@ -80,11 +76,9 @@ public CatalogSource(String apiKey, URL sourceUrl) throws MalformedURLException * Administration Console * */ - public CatalogSource(String apiKey, String organizationId, String sourceId) { + public static CatalogSource fromPlatformUrl(String apiKey, String organizationId, String sourceId) { PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); - this.sourceId = sourceId; - this.platformClient = new PlatformClient(apiKey, organizationId, - platformUrl); + return new CatalogSource(apiKey, organizationId, sourceId, platformUrl); } /** @@ -121,23 +115,40 @@ public CatalogSource(String apiKey, String organizationId, String sourceId) { * URL endpoint. * You can use the {@link PlatformUrl} when your * organization is located in a non-default Coveo - * environement and/or region. + * 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 CatalogSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { - this.sourceId = sourceId; - this.platformClient = new PlatformClient(apiKey, organizationId, - platformUrl); + 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.sourceId; + return this.urlExtractor.getSourceId(); } @Override - public PlatformClient getPlatformClient() { - return this.platformClient; + public String getApiKey() { + return this.apiKey; } } diff --git a/src/main/java/com/coveo/pushapiclient/PushSource.java b/src/main/java/com/coveo/pushapiclient/PushSource.java index 92c777bf..4a17f9a5 100644 --- a/src/main/java/com/coveo/pushapiclient/PushSource.java +++ b/src/main/java/com/coveo/pushapiclient/PushSource.java @@ -9,17 +9,28 @@ // TODO: LENS-851 - Make public when ready class PushSource implements PushEnabledSource { + private final String apiKey; + private final ApiUrl urlExtractor; private final PlatformClient platformClient; - private final String sourceId; @Override - public PlatformClient getPlatformClient() { - return this.platformClient; + public String getOrganizationId() { + return this.urlExtractor.getOrganizationId(); + } + + @Override + public PlatformUrl getPlatformUrl() { + return this.urlExtractor.getPlatformUrl(); } @Override public String getId() { - return this.sourceId; + return this.urlExtractor.getSourceId(); + } + + @Override + public String getApiKey() { + return this.apiKey; } /** @@ -55,17 +66,15 @@ public String getId() { * @throws MalformedURLException */ public PushSource(String apiKey, URL sourceUrl) throws MalformedURLException { - ApiUrl parser = new ApiUrl(sourceUrl); - PlatformUrl platformUrl = parser.getPlatformUrl(); - String organizationId = parser.getOrganizationId(); - this.sourceId = parser.getSourceId(); - this.platformClient = new PlatformClient(apiKey, organizationId, - platformUrl); + 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 from its - * Stream API URL + * Create a Push source instance * * @param apiKey The API key used for all operations regarding your * source. @@ -94,16 +103,13 @@ public PushSource(String apiKey, URL sourceUrl) throws MalformedURLException { * Administration Console * */ - public PushSource(String apiKey, String organizationId, String sourceId) { + public static PushSource fromPlatformUrl(String apiKey, String organizationId, String sourceId) { PlatformUrl platformUrl = new PlatformUrl(PlatformUrl.DEFAULT_ENVIRONMENT, PlatformUrl.DEFAULT_REGION); - this.sourceId = sourceId; - this.platformClient = new PlatformClient(apiKey, organizationId, - platformUrl); + return new PushSource(apiKey, organizationId, sourceId, platformUrl); } /** - * Create a Push source instance from its - * Stream API URL + * Create a Push source instance * * @param apiKey The API key used for all operations regarding your * source. @@ -135,13 +141,21 @@ public PushSource(String apiKey, String organizationId, String sourceId) { * URL endpoint. * You can use the {@link PlatformUrl} when your * organization is located in a non-default Coveo - * environement and/or region. + * 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 PushSource(String apiKey, String organizationId, String sourceId, PlatformUrl platformUrl) { - this.sourceId = sourceId; - this.platformClient = new PlatformClient(apiKey, organizationId, - platformUrl); + 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); } /** @@ -202,7 +216,7 @@ public HttpResponse deleteSecurityIdentity(String securityProviderId, */ public HttpResponse updateSourceStatus(PushAPIStatus status) throws IOException, InterruptedException { - return this.platformClient.updateSourceStatus(this.sourceId, status); + return this.platformClient.updateSourceStatus(this.getId(), status); } /** @@ -277,7 +291,7 @@ public HttpResponse addOrUpdateDocument(DocumentBuilder docBuilder) CompressionType compressionType = docBuilder.getDocument().compressedBinaryData != null ? docBuilder.getDocument().compressedBinaryData.getCompressionType() : CompressionType.UNCOMPRESSED; - return this.platformClient.pushDocument(this.sourceId, docBuilder.marshal(), docBuilder.getDocument().uri, + return this.platformClient.pushDocument(this.getId(), docBuilder.marshal(), docBuilder.getDocument().uri, compressionType); } @@ -294,7 +308,7 @@ public HttpResponse addOrUpdateDocument(DocumentBuilder docBuilder) */ public HttpResponse deleteDocument(String documentId, Boolean deleteChildren) throws IOException, InterruptedException { - return this.platformClient.deleteDocument(this.sourceId, documentId, deleteChildren); + return this.platformClient.deleteDocument(this.getId(), documentId, deleteChildren); } }