From 35fb35409518c25831941193515b5f7051cd85b8 Mon Sep 17 00:00:00 2001 From: maryan-opti Date: Mon, 13 Jan 2025 15:21:13 +0200 Subject: [PATCH 1/4] handle Engagement payload as JSON String --- readme.md | 6 +-- .../optimove/sdk/engagement/Engagement.java | 48 ++++++++++++++++++ .../sdk/engagement/EngagementConfig.java | 49 +++++++++++++++++++ .../optimove/sdk/engagement/Metadata.java | 2 +- .../sdk/engagement/StorageSingleton.java | 2 - src/main/java/org/example/Main.java | 13 +++-- src/test/java/EngagementTest.java | 2 +- 7 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 src/main/java/optimove/sdk/engagement/EngagementConfig.java diff --git a/readme.md b/readme.md index d35f276..0bd8751 100644 --- a/readme.md +++ b/readme.md @@ -41,12 +41,12 @@ public class Main { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(Main.class); - Engagement engagement = new Engagement(null, 1, "bucket-name", "customers-folder/customers", "metadata-path/metadata_287934", logger); + Engagement engagement = new Engagement("{\r\n \"EventTypeID\": 14,\r\n \"TimeStamp\": \"2025-01-08 08:58\",\r\n \"CampaignID\": 1111,\r\n \"EngagementID\": 1111,\r\n \"TenantID\": 1111,\r\n \"BucketName\": \"bucketName\",\r\n \"CustomersFolderPath\": \"path\",\r\n \"MetadataFilePath\": \"pathCustomers\",\r\n \"DecryptionKey\": \"some-secret-key\",\r\n \"ChannelID\": 1111\r\n}", logger); Metadata metadata = engagement.getMetadata(); - System.out.println(metadata.getNumberOfFiles()); + System.out.println(metadata.getNumberOfBatches()); - for (int fileNumber = 1; fileNumber <= metadata.getNumberOfFiles(); fileNumber++) { + for (int fileNumber = 1; fileNumber <= metadata.getNumberOfBatches(); fileNumber++) { System.out.println("file number: " + fileNumber); try (DataFileStream dataFileReader = engagement.getCustomerBatchById(fileNumber)) { diff --git a/src/main/java/optimove/sdk/engagement/Engagement.java b/src/main/java/optimove/sdk/engagement/Engagement.java index 4f89d8b..7706801 100644 --- a/src/main/java/optimove/sdk/engagement/Engagement.java +++ b/src/main/java/optimove/sdk/engagement/Engagement.java @@ -1,5 +1,6 @@ package optimove.sdk.engagement; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.cloud.storage.Blob; import com.google.cloud.ReadChannel; @@ -25,6 +26,53 @@ public Engagement(String decryptionKey, int tenantID, String bucketName, String this.logger = logger; } + // Constructor that accepts JSON string and logger + public Engagement(String jsonConfig, Logger logger) { + if (jsonConfig == null || logger == null) { + throw new IllegalArgumentException("Neither jsonConfig nor logger can be null"); + } + + try { + ObjectMapper mapper = new ObjectMapper(); + EngagementConfig config = mapper.readValue(jsonConfig, EngagementConfig.class); + this.settings = createSettingsFromConfig(config); + this.logger = logger; + } catch (IOException e) { + throw new RuntimeException("Failed to parse engagement configuration: " + e.getMessage(), e); + } + } + + // Constructor that accepts any object and logger + public Engagement(Object configObject, Logger logger) { + if (configObject == null || logger == null) { + throw new IllegalArgumentException("Neither configObject nor logger can be null"); + } + + try { + ObjectMapper mapper = new ObjectMapper(); + // First convert the object to a JSON string + String jsonString = mapper.writeValueAsString(configObject); + // Then convert it to our EngagementConfig class + EngagementConfig config = mapper.readValue(jsonString, EngagementConfig.class); + + this.settings = createSettingsFromConfig(config); + this.logger = logger; + } catch (IOException e) { + throw new RuntimeException("Failed to convert object to engagement configuration: " + e.getMessage(), e); + } + } + + // Helper method to create settings from config + private EngagementSettings createSettingsFromConfig(EngagementConfig config) { + return new EngagementSettings( + config.getDecryptionKey(), + config.getTenantID(), + config.getBucketName(), + config.getCustomersFolderPath(), + config.getMetadataFilePath() + ); + } + public Metadata getMetadata() { try { Blob fileBlob = StorageSingleton.getBlob(this.settings.getBucketName(), this.settings.getMetadataFilePath()); diff --git a/src/main/java/optimove/sdk/engagement/EngagementConfig.java b/src/main/java/optimove/sdk/engagement/EngagementConfig.java new file mode 100644 index 0000000..a316cf3 --- /dev/null +++ b/src/main/java/optimove/sdk/engagement/EngagementConfig.java @@ -0,0 +1,49 @@ +package optimove.sdk.engagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +class EngagementConfig { + @JsonProperty("DecryptionKey") + private String decryptionKey; + + @JsonProperty("TenantID") + private int tenantID; + + @JsonProperty("BucketName") + private String bucketName; + + @JsonProperty("CustomersFolderPath") + private String customersFolderPath; + + @JsonProperty("MetadataFilePath") + private String metadataFilePath; + + @JsonProperty("EventTypeID") + private int eventTypeId; + + @JsonProperty("TimeStamp") + private String timestamp; + + @JsonProperty("CampaignID") + private int campaignId; + + @JsonProperty("EngagementID") + private int engagementId; + + @JsonProperty("ChannelID") + private int channelId; + + // Getters + public String getDecryptionKey() { return decryptionKey; } + public int getTenantID() { return tenantID; } + public String getBucketName() { return bucketName; } + public String getCustomersFolderPath() { return customersFolderPath; } + public String getMetadataFilePath() { return metadataFilePath; } + public int getEventTypeId() { return eventTypeId; } + public String getTimestamp() { return timestamp; } + public int getCampaignId() { return campaignId; } + public int getEngagementId() { return engagementId; } + public int getChannelId() { return channelId; } +} diff --git a/src/main/java/optimove/sdk/engagement/Metadata.java b/src/main/java/optimove/sdk/engagement/Metadata.java index 1095f75..a950ad2 100644 --- a/src/main/java/optimove/sdk/engagement/Metadata.java +++ b/src/main/java/optimove/sdk/engagement/Metadata.java @@ -88,7 +88,7 @@ public long getNumberOfCustomers() { return NumberOfCustomers; } - public long getNumberOfFiles() { + public long getNumberOfBatches() { return NumberOfFiles; } diff --git a/src/main/java/optimove/sdk/engagement/StorageSingleton.java b/src/main/java/optimove/sdk/engagement/StorageSingleton.java index b2295b0..3cf3fc7 100644 --- a/src/main/java/optimove/sdk/engagement/StorageSingleton.java +++ b/src/main/java/optimove/sdk/engagement/StorageSingleton.java @@ -12,14 +12,12 @@ public class StorageSingleton { private static Storage instance = null; - private static final String projectId = "optimoveSDK"; private StorageSingleton() { } public static Storage getInstance() { if(instance == null) { instance = StorageOptions.newBuilder() - .setProjectId(projectId) .build() .getService(); } diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java index 9827a32..1529411 100644 --- a/src/main/java/org/example/Main.java +++ b/src/main/java/org/example/Main.java @@ -3,10 +3,13 @@ import org.apache.avro.file.DataFileStream; import org.apache.avro.generic.GenericRecord; import java.io.IOException; +import java.time.Duration; +import java.time.Instant; import optimove.sdk.engagement.Engagement; import optimove.sdk.engagement.Metadata; +import org.apache.commons.lang3.time.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,15 +17,17 @@ public class Main { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(Main.class); - Engagement engagement = new Engagement(null, 1, "bucket-name", "customers-folder/customers", "metadata-path/metadata_287934", logger); + Engagement engagement = new Engagement("{\r\n \"EventTypeID\": 14,\r\n \"TimeStamp\": \"2025-01-08 08:58\",\r\n \"CampaignID\": 1111,\r\n \"EngagementID\": 1111,\r\n \"TenantID\": 1111,\r\n \"BucketName\": \"bucketName\",\r\n \"CustomersFolderPath\": \"path\",\r\n \"MetadataFilePath\": \"pathCustomers\",\r\n \"DecryptionKey\": \"some-secret-key\",\r\n \"ChannelID\": 1111\r\n}", logger); Metadata metadata = engagement.getMetadata(); - System.out.println(metadata.getNumberOfFiles()); + System.out.println(metadata.getNumberOfBatches()); - for (int fileNumber = 1; fileNumber <= metadata.getNumberOfFiles(); fileNumber++) { + for (int fileNumber = 1; fileNumber <= metadata.getNumberOfBatches(); fileNumber++) { System.out.println("file number: " + fileNumber); - try (DataFileStream dataFileReader = engagement.getCustomerBatchById(fileNumber)) { + DataFileStream dataFileReader = null; + try { + dataFileReader = engagement.getCustomerBatchById(fileNumber); GenericRecord record = null; while (dataFileReader.hasNext()) { record = dataFileReader.next(record); diff --git a/src/test/java/EngagementTest.java b/src/test/java/EngagementTest.java index d7f1fe5..61a8ff5 100644 --- a/src/test/java/EngagementTest.java +++ b/src/test/java/EngagementTest.java @@ -68,7 +68,7 @@ public void test_retrieving_metadata_from_valid_bucket_and_file_path() { // Verify the expected behavior assertNotNull(metadata); - assumeTrue(metadata.getNumberOfFiles() == 3); + assumeTrue(metadata.getNumberOfBatches() == 3); assumeTrue(metadata.getNumberOfCustomers() == 300); assumeTrue(metadata.getCampaignPlanID() == 10); assumeTrue(metadata.getCampaignID() == 1); From c27173cc23ca1d4fdf3273b8fb1fc0bd52469979 Mon Sep 17 00:00:00 2001 From: maryan-opti Date: Mon, 13 Jan 2025 15:30:41 +0200 Subject: [PATCH 2/4] update pom dependency --- pom.xml | 4 ++-- src/main/java/org/example/Main.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index ee79d13..893f7f2 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ com.google.cloud google-cloud-storage - 2.34.0 + 2.46.0 com.fasterxml.jackson.dataformat @@ -62,7 +62,7 @@ org.apache.avro avro - 1.11.3 + 1.11.4 org.apache.commons diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java index 1529411..ecfce35 100644 --- a/src/main/java/org/example/Main.java +++ b/src/main/java/org/example/Main.java @@ -17,7 +17,7 @@ public class Main { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(Main.class); - Engagement engagement = new Engagement("{\r\n \"EventTypeID\": 14,\r\n \"TimeStamp\": \"2025-01-08 08:58\",\r\n \"CampaignID\": 1111,\r\n \"EngagementID\": 1111,\r\n \"TenantID\": 1111,\r\n \"BucketName\": \"bucketName\",\r\n \"CustomersFolderPath\": \"path\",\r\n \"MetadataFilePath\": \"pathCustomers\",\r\n \"DecryptionKey\": \"some-secret-key\",\r\n \"ChannelID\": 1111\r\n}", logger); + Engagement engagement = new Engagement("{\r\n \"EventTypeID\": 14,\r\n \"TimeStamp\": \"2025-01-08 08:58\",\r\n \"CampaignID\": 8677,\r\n \"EngagementID\": 9061,\r\n \"TenantID\": 593,\r\n \"BucketName\": \"optigration-external-eu\",\r\n \"CustomersFolderPath\": \"593_2025-01-08 09 00_optigration demo_507_9061/customers\",\r\n \"MetadataFilePath\": \"593_2025-01-08 09 00_optigration demo_507_9061/metadata_9061\",\r\n \"DecryptionKey\": \"Sdy+upo5M2yFYOWYqk3cxBoZHq2vDNaXRZeqxUSITIU=\",\r\n \"ChannelID\": 507\r\n}", logger); Metadata metadata = engagement.getMetadata(); System.out.println(metadata.getNumberOfBatches()); From d16e438d850b54cca144d8b29fd9c8c4840edc67 Mon Sep 17 00:00:00 2001 From: maryan-opti Date: Tue, 14 Jan 2025 10:22:50 +0200 Subject: [PATCH 3/4] fix pom file --- pom.xml | 12 +++++++++++- readme.md | 14 +++++++------- .../java/optimove/sdk/engagement/Metadata.java | 4 ++++ src/main/java/org/example/Main.java | 8 ++++---- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 893f7f2..e3d290b 100644 --- a/pom.xml +++ b/pom.xml @@ -42,12 +42,22 @@ http://github.com/optimove/Optimove-SDK-Engagement-java/tree/master + + + + com.google.cloud + libraries-bom + 26.52.0 + pom + import + + + com.google.cloud google-cloud-storage - 2.46.0 com.fasterxml.jackson.dataformat diff --git a/readme.md b/readme.md index 0bd8751..db66f5a 100644 --- a/readme.md +++ b/readme.md @@ -46,10 +46,10 @@ public class Main { Metadata metadata = engagement.getMetadata(); System.out.println(metadata.getNumberOfBatches()); - for (int fileNumber = 1; fileNumber <= metadata.getNumberOfBatches(); fileNumber++) { - System.out.println("file number: " + fileNumber); + for (int batchNumber = 1; batchNumber <= metadata.getNumberOfBatches(); batchNumber++) { + System.out.println("batch number: " + batchNumber); - try (DataFileStream dataFileReader = engagement.getCustomerBatchById(fileNumber)) { + try (DataFileStream dataFileReader = engagement.getCustomerBatchById(batchNumber)) { GenericRecord record = null; while (dataFileReader.hasNext()) { record = dataFileReader.next(record); @@ -86,27 +86,27 @@ logger.error("Failed to retrieve metadata: " + e.getMessage(), e); } ``` ### Customer Data Retrieval -When retrieving customer data for an engagement, the SDK may encounter errors such as a missing or malformed customer data file, or an invalid file ID. +When retrieving customer data for an engagement, the SDK may encounter errors such as a missing or malformed customer data file, or an invalid batch ID. In the case of a missing or malformed customer data file, the getCustomerBatchById() method will throw a RuntimeException with a message indicating the cause of the error. For example: ```java -try (DataFileStream dataFileReader = engagement.getCustomerBatchById(fileNumber)) { +try (DataFileStream dataFileReader = engagement.getCustomerBatchById(batchNumber)) { // use dataFileReader } catch (RuntimeException e) { logger.error("Failed to get customer batch by id: " + e.getMessage(), e); // handle error } ``` -If an invalid file ID is provided, the getCustomerBatchById() method will throw an IllegalArgumentException with a message indicating the cause of the error. For example: +If an invalid batch ID is provided, the getCustomerBatchById() method will throw an IllegalArgumentException with a message indicating the cause of the error. For example: ```java try (DataFileStream dataFileReader = engagement.getCustomerBatchById(-1)) { // use dataFileReader } catch (IllegalArgumentException e) { -logger.error("Invalid file id: " + e.getMessage(), e); +logger.error("Invalid batch id: " + e.getMessage(), e); // handle error } ``` diff --git a/src/main/java/optimove/sdk/engagement/Metadata.java b/src/main/java/optimove/sdk/engagement/Metadata.java index a950ad2..360dd3e 100644 --- a/src/main/java/optimove/sdk/engagement/Metadata.java +++ b/src/main/java/optimove/sdk/engagement/Metadata.java @@ -88,6 +88,10 @@ public long getNumberOfCustomers() { return NumberOfCustomers; } + public long getNumberOfFiles() { + return NumberOfFiles; + } + public long getNumberOfBatches() { return NumberOfFiles; } diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java index ecfce35..7d9b953 100644 --- a/src/main/java/org/example/Main.java +++ b/src/main/java/org/example/Main.java @@ -17,17 +17,17 @@ public class Main { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(Main.class); - Engagement engagement = new Engagement("{\r\n \"EventTypeID\": 14,\r\n \"TimeStamp\": \"2025-01-08 08:58\",\r\n \"CampaignID\": 8677,\r\n \"EngagementID\": 9061,\r\n \"TenantID\": 593,\r\n \"BucketName\": \"optigration-external-eu\",\r\n \"CustomersFolderPath\": \"593_2025-01-08 09 00_optigration demo_507_9061/customers\",\r\n \"MetadataFilePath\": \"593_2025-01-08 09 00_optigration demo_507_9061/metadata_9061\",\r\n \"DecryptionKey\": \"Sdy+upo5M2yFYOWYqk3cxBoZHq2vDNaXRZeqxUSITIU=\",\r\n \"ChannelID\": 507\r\n}", logger); + Engagement engagement = new Engagement("{\r\n \"EventTypeID\": 14,\r\n \"TimeStamp\": \"2025-01-08 08:58\",\r\n \"CampaignID\": 1111,\r\n \"EngagementID\": 1111,\r\n \"TenantID\": 1111,\r\n \"BucketName\": \"bucketName\",\r\n \"CustomersFolderPath\": \"path\",\r\n \"MetadataFilePath\": \"pathCustomers\",\r\n \"DecryptionKey\": \"some-secret-key\",\r\n \"ChannelID\": 1111\r\n}", logger); Metadata metadata = engagement.getMetadata(); System.out.println(metadata.getNumberOfBatches()); - for (int fileNumber = 1; fileNumber <= metadata.getNumberOfBatches(); fileNumber++) { - System.out.println("file number: " + fileNumber); + for (int batchNumber = 1; batchNumber <= metadata.getNumberOfBatches(); batchNumber++) { + System.out.println("batch number: " + batchNumber); DataFileStream dataFileReader = null; try { - dataFileReader = engagement.getCustomerBatchById(fileNumber); + dataFileReader = engagement.getCustomerBatchById(batchNumber); GenericRecord record = null; while (dataFileReader.hasNext()) { record = dataFileReader.next(record); From 95786bc10b51166a94d4d788177546f842da9030 Mon Sep 17 00:00:00 2001 From: maryan-opti Date: Wed, 15 Jan 2025 17:00:41 +0200 Subject: [PATCH 4/4] handle unauth blob get --- src/main/java/optimove/sdk/engagement/Engagement.java | 2 +- src/main/java/optimove/sdk/engagement/StorageSingleton.java | 6 ++++-- src/test/java/EngagementTest.java | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/optimove/sdk/engagement/Engagement.java b/src/main/java/optimove/sdk/engagement/Engagement.java index 7706801..872adff 100644 --- a/src/main/java/optimove/sdk/engagement/Engagement.java +++ b/src/main/java/optimove/sdk/engagement/Engagement.java @@ -75,7 +75,7 @@ private EngagementSettings createSettingsFromConfig(EngagementConfig config) { public Metadata getMetadata() { try { - Blob fileBlob = StorageSingleton.getBlob(this.settings.getBucketName(), this.settings.getMetadataFilePath()); + Blob fileBlob = StorageSingleton.getBlob(this.settings.getBucketName(), this.settings.getMetadataFilePath(), this.settings.getDecryptionKey()); String metadataString = StorageSingleton.blobToString(fileBlob, this.settings.getDecryptionKey()); return MetadataService.jsonStringToMetadata(metadataString); diff --git a/src/main/java/optimove/sdk/engagement/StorageSingleton.java b/src/main/java/optimove/sdk/engagement/StorageSingleton.java index 3cf3fc7..bfae4a6 100644 --- a/src/main/java/optimove/sdk/engagement/StorageSingleton.java +++ b/src/main/java/optimove/sdk/engagement/StorageSingleton.java @@ -23,9 +23,11 @@ public static Storage getInstance() { } return instance; } - public static Blob getBlob(String bucketName, String srcFileName) { - return getInstance().get(bucketName, srcFileName); + return getInstance().get(BlobId.of(bucketName, srcFileName)); + } + public static Blob getBlob(String bucketName, String srcFileName, String decryptionKey) { + return getInstance().get(BlobId.of(bucketName, srcFileName), Storage.BlobGetOption.decryptionKey(decryptionKey)); } public static ReadChannel getReadChanel(String bucketName, String srcFileName) { return getInstance().reader(BlobId.of(bucketName, srcFileName)); diff --git a/src/test/java/EngagementTest.java b/src/test/java/EngagementTest.java index 61a8ff5..e62d69f 100644 --- a/src/test/java/EngagementTest.java +++ b/src/test/java/EngagementTest.java @@ -57,7 +57,7 @@ public void test_retrieving_metadata_from_valid_bucket_and_file_path() { try (MockedStatic classMock = mockStatic(StorageSingleton.class)) { - classMock.when(() -> StorageSingleton.getBlob(anyString(), anyString())).thenReturn(fileBlob); + classMock.when(() -> StorageSingleton.getBlob(anyString(), anyString(), anyString())).thenReturn(fileBlob); classMock.when(() -> StorageSingleton.blobToString(eq(fileBlob), any(String.class))).thenReturn(metadataString); classMock.when(() -> StorageSingleton.getReadChanel(anyString(), anyString(), anyString())).thenReturn(readChannel);