diff --git a/pom.xml b/pom.xml index ee79d13..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.34.0 com.fasterxml.jackson.dataformat @@ -62,7 +72,7 @@ org.apache.avro avro - 1.11.3 + 1.11.4 org.apache.commons diff --git a/readme.md b/readme.md index d35f276..db66f5a 100644 --- a/readme.md +++ b/readme.md @@ -41,15 +41,15 @@ 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++) { - 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/Engagement.java b/src/main/java/optimove/sdk/engagement/Engagement.java index 4f89d8b..872adff 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,9 +26,56 @@ 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()); + 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/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..360dd3e 100644 --- a/src/main/java/optimove/sdk/engagement/Metadata.java +++ b/src/main/java/optimove/sdk/engagement/Metadata.java @@ -92,6 +92,10 @@ public long getNumberOfFiles() { return NumberOfFiles; } + public long getNumberOfBatches() { + return NumberOfFiles; + } + public long getPlanDetailChannelID() { return PlanDetailChannelID; } diff --git a/src/main/java/optimove/sdk/engagement/StorageSingleton.java b/src/main/java/optimove/sdk/engagement/StorageSingleton.java index b2295b0..bfae4a6 100644 --- a/src/main/java/optimove/sdk/engagement/StorageSingleton.java +++ b/src/main/java/optimove/sdk/engagement/StorageSingleton.java @@ -12,22 +12,22 @@ 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(); } 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/main/java/org/example/Main.java b/src/main/java/org/example/Main.java index 9827a32..7d9b953 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++) { - 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)) { + DataFileStream dataFileReader = null; + try { + dataFileReader = engagement.getCustomerBatchById(batchNumber); 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..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); @@ -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);