Copilot commented on code in PR #10318:
URL: https://github.com/apache/ozone/pull/10318#discussion_r3277252823


##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/s3/S3EventNotificationStrategy.java:
##########
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.eventlistener.s3;
+
+import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.commons.lang3.StringUtils;
+import 
org.apache.hadoop.ozone.om.eventlistener.OMEventListenerNotificationStrategy;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.OzoneEventDataKey;
+import org.apache.hadoop.ozone.om.helpers.OmCompletedRequestInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a notification strategy to generate events according to S3
+ * notification semantics.
+ */
+public class S3EventNotificationStrategy implements 
OMEventListenerNotificationStrategy {
+  public static final Logger LOG = 
LoggerFactory.getLogger(S3EventNotificationStrategy.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+
+  @Override
+  public List<String> determineEventsForOperation(OmCompletedRequestInfo 
requestInfo) {
+
+    switch (requestInfo.getCmdType()) {
+    case CreateKey:
+    case CommitKey:
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              Collections.emptyMap())
+      );
+    case CreateFile:
+      OmCompletedRequestInfo.OperationArgs.CreateFileArgs createFileArgs
+          = (OmCompletedRequestInfo.OperationArgs.CreateFileArgs) 
requestInfo.getOpArgs();
+
+      // XXX: ozoneEventData is an Ozone extension. Its is unclear if this
+      // schema makes sense but the general S3 schema is somewhat
+      // freeform.  These arguments are more informational than
+      // required so it is unclear as to their necessity.
+      Map<String, Object> renameEventData = new HashMap<>();
+      renameEventData.put(OzoneEventDataKey.IS_DIRECTORY.toString(), false);
+      renameEventData.put(OzoneEventDataKey.IS_RECURSIVE.toString(), 
createFileArgs.isRecursive());
+      renameEventData.put(OzoneEventDataKey.IS_OVERWRITE.toString(), 
createFileArgs.isOverwrite());
+
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              renameEventData)
+      );
+    case CreateDirectory:
+      // XXX: ozoneEventData is an Ozone extension. Its is unclear if this
+      // schema makes sense but the general S3 schema is somewhat
+      // freeform.  These arguments are more informational than
+      // required so it is unclear as to their necessity.
+      Map<String, Object> createEventData = new HashMap<>();
+      createEventData.put(OzoneEventDataKey.IS_DIRECTORY.toString(), true);
+
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              createEventData)
+      );
+    case DeleteKey:
+      return Collections.singletonList(createS3Event("ObjectRemoved:Delete",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              Collections.emptyMap())
+      );
+    case RenameKey:
+      OmCompletedRequestInfo.OperationArgs.RenameKeyArgs renameKeyArgs
+          = (OmCompletedRequestInfo.OperationArgs.RenameKeyArgs) 
requestInfo.getOpArgs();
+
+      String renameFromKey = 
S3OzoneEventKeyFormatter.getOzoneKey(requestInfo.getVolumeName(),
+                                                      
requestInfo.getBucketName(),
+                                                      
requestInfo.getKeyName());
+
+      // XXX: it would be good to be able to convey that this was a
+      // file vs directory rename
+      Map<String, Object> ozoneEventData = new HashMap<>();
+      ozoneEventData.put(OzoneEventDataKey.RENAME_FROM_KEY.toString(), 
renameFromKey);
+
+      // NOTE: ObjectRenamed:Rename is an Ozone extension as is the
+      // ozoneEventData map in the S3 event schema.
+      return Collections.singletonList(createS3Event("ObjectRenamed:Rename",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              renameKeyArgs.getToKeyName(),
+              ozoneEventData)
+      );
+    default:
+      LOG.info("No events for operation {} on {}",

Review Comment:
   The default branch logs at INFO for every operation type that does not 
produce an event, which may be extremely noisy in production. Consider lowering 
this to DEBUG/TRACE or rate-limiting it.
   



##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/s3/S3EventNotificationStrategy.java:
##########
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.eventlistener.s3;
+
+import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.commons.lang3.StringUtils;
+import 
org.apache.hadoop.ozone.om.eventlistener.OMEventListenerNotificationStrategy;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.OzoneEventDataKey;
+import org.apache.hadoop.ozone.om.helpers.OmCompletedRequestInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a notification strategy to generate events according to S3
+ * notification semantics.
+ */
+public class S3EventNotificationStrategy implements 
OMEventListenerNotificationStrategy {
+  public static final Logger LOG = 
LoggerFactory.getLogger(S3EventNotificationStrategy.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+
+  @Override
+  public List<String> determineEventsForOperation(OmCompletedRequestInfo 
requestInfo) {
+
+    switch (requestInfo.getCmdType()) {
+    case CreateKey:
+    case CommitKey:
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              Collections.emptyMap())
+      );
+    case CreateFile:
+      OmCompletedRequestInfo.OperationArgs.CreateFileArgs createFileArgs
+          = (OmCompletedRequestInfo.OperationArgs.CreateFileArgs) 
requestInfo.getOpArgs();
+
+      // XXX: ozoneEventData is an Ozone extension. Its is unclear if this
+      // schema makes sense but the general S3 schema is somewhat
+      // freeform.  These arguments are more informational than
+      // required so it is unclear as to their necessity.
+      Map<String, Object> renameEventData = new HashMap<>();
+      renameEventData.put(OzoneEventDataKey.IS_DIRECTORY.toString(), false);
+      renameEventData.put(OzoneEventDataKey.IS_RECURSIVE.toString(), 
createFileArgs.isRecursive());
+      renameEventData.put(OzoneEventDataKey.IS_OVERWRITE.toString(), 
createFileArgs.isOverwrite());
+
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              renameEventData)
+      );
+    case CreateDirectory:
+      // XXX: ozoneEventData is an Ozone extension. Its is unclear if this
+      // schema makes sense but the general S3 schema is somewhat
+      // freeform.  These arguments are more informational than
+      // required so it is unclear as to their necessity.
+      Map<String, Object> createEventData = new HashMap<>();
+      createEventData.put(OzoneEventDataKey.IS_DIRECTORY.toString(), true);
+
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              createEventData)
+      );
+    case DeleteKey:
+      return Collections.singletonList(createS3Event("ObjectRemoved:Delete",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              Collections.emptyMap())
+      );
+    case RenameKey:
+      OmCompletedRequestInfo.OperationArgs.RenameKeyArgs renameKeyArgs
+          = (OmCompletedRequestInfo.OperationArgs.RenameKeyArgs) 
requestInfo.getOpArgs();
+
+      String renameFromKey = 
S3OzoneEventKeyFormatter.getOzoneKey(requestInfo.getVolumeName(),
+                                                      
requestInfo.getBucketName(),
+                                                      
requestInfo.getKeyName());
+
+      // XXX: it would be good to be able to convey that this was a
+      // file vs directory rename
+      Map<String, Object> ozoneEventData = new HashMap<>();
+      ozoneEventData.put(OzoneEventDataKey.RENAME_FROM_KEY.toString(), 
renameFromKey);
+
+      // NOTE: ObjectRenamed:Rename is an Ozone extension as is the
+      // ozoneEventData map in the S3 event schema.
+      return Collections.singletonList(createS3Event("ObjectRenamed:Rename",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              renameKeyArgs.getToKeyName(),
+              ozoneEventData)
+      );
+    default:
+      LOG.info("No events for operation {} on {}",
+           requestInfo.getCmdType(),
+           requestInfo.getKeyName());
+      return Collections.emptyList();
+    }
+  }
+
+  static String createS3Event(String eventName,
+                              String volumeName,
+                              String bucketName,
+                              String keyName,
+                              Map<String, Object> ozoneEventData) {
+    try {
+      String objectKey = S3OzoneEventKeyFormatter.getOzoneKey(volumeName, 
bucketName, keyName);
+      String bucketArn = "arn:aws:s3:::" + volumeName + "." + bucketName;
+      Instant eventTime = Instant.now();
+      String etag = UUID.randomUUID().toString();
+
+      S3EventNotification event = new S3EventNotificationBuilder(objectKey, 
bucketName, bucketArn,
+                                                                 eventName, 
eventTime, etag)
+          .addAllEventData(ozoneEventData)
+          .build();
+
+      return MAPPER.writer().writeValueAsString(event);
+    } catch (Exception ex) {
+      LOG.info("------------> {}", "failed");
+      return null;

Review Comment:
   createS3Event swallows all exceptions and returns null, which will propagate 
as a null event payload (eg, via Collections.singletonList(null)) and can lead 
to Kafka publishing tombstones or NPEs downstream. Please log at ERROR with the 
exception, and avoid returning null (return empty/Optional or rethrow so the 
caller can skip updating the seek position).
   



##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/s3/S3EventNotificationStrategy.java:
##########
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.eventlistener.s3;
+
+import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.commons.lang3.StringUtils;
+import 
org.apache.hadoop.ozone.om.eventlistener.OMEventListenerNotificationStrategy;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.OzoneEventDataKey;
+import org.apache.hadoop.ozone.om.helpers.OmCompletedRequestInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a notification strategy to generate events according to S3
+ * notification semantics.
+ */
+public class S3EventNotificationStrategy implements 
OMEventListenerNotificationStrategy {
+  public static final Logger LOG = 
LoggerFactory.getLogger(S3EventNotificationStrategy.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+
+  @Override
+  public List<String> determineEventsForOperation(OmCompletedRequestInfo 
requestInfo) {
+
+    switch (requestInfo.getCmdType()) {
+    case CreateKey:
+    case CommitKey:
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              Collections.emptyMap())
+      );
+    case CreateFile:
+      OmCompletedRequestInfo.OperationArgs.CreateFileArgs createFileArgs
+          = (OmCompletedRequestInfo.OperationArgs.CreateFileArgs) 
requestInfo.getOpArgs();
+
+      // XXX: ozoneEventData is an Ozone extension. Its is unclear if this
+      // schema makes sense but the general S3 schema is somewhat
+      // freeform.  These arguments are more informational than
+      // required so it is unclear as to their necessity.
+      Map<String, Object> renameEventData = new HashMap<>();
+      renameEventData.put(OzoneEventDataKey.IS_DIRECTORY.toString(), false);
+      renameEventData.put(OzoneEventDataKey.IS_RECURSIVE.toString(), 
createFileArgs.isRecursive());
+      renameEventData.put(OzoneEventDataKey.IS_OVERWRITE.toString(), 
createFileArgs.isOverwrite());
+
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              renameEventData)

Review Comment:
   Variable name `renameEventData` is misleading in the CreateFile case (it is 
create-file metadata, not rename metadata). Rename it to something like 
`createFileEventData` to avoid confusion and reduce the chance of copy/paste 
errors as the strategy grows.
   



##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/OMEventListenerKafkaPublisher.java:
##########
@@ -102,24 +123,19 @@ public void stop() {
   public void handleCompletedRequest(OmCompletedRequestInfo 
completedRequestInfo) {
     LOG.debug("Processing {}", completedRequestInfo);
 
-    // stub event until we implement a strategy to convert the events to
-    // a user facing schema (e.g. S3)
-    String event = String.format("{\"key\":\"%s/%s/%s\", \"type\":\"%s\"}",
-        completedRequestInfo.getVolumeName(),
-        completedRequestInfo.getBucketName(),
-        completedRequestInfo.getKeyName(),
-        String.valueOf(completedRequestInfo.getCmdType()));
+    List<String> eventsToSend = 
notificationStrategy.determineEventsForOperation(completedRequestInfo);
 
-    LOG.debug("Sending {}", event);
-
-    try {
-      kafkaClient.send(event);
-    } catch (IOException ex) {
-      LOG.error("Failure to send event {}", event, ex);
-      return;
+    // loop over events and send them to our kafka sink
+    for (String event : eventsToSend) {
+      try {
+        kafkaClient.send(event);
+      } catch (IOException ex) {
+        LOG.error("Failure to send event {}", event, ex);
+        return;
+      }

Review Comment:
   handleCompletedRequest sends every string returned by the strategy without 
validating it. Since S3EventNotificationStrategy#createS3Event currently 
returns null on failure, this can result in publishing null messages to Kafka 
and still advancing the seek position on partial failures. Consider filtering 
out null/blank events and treating generation failures as an error (skip seek 
update).



##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/s3/S3EventNotificationStrategy.java:
##########
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.eventlistener.s3;
+
+import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.commons.lang3.StringUtils;
+import 
org.apache.hadoop.ozone.om.eventlistener.OMEventListenerNotificationStrategy;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.OzoneEventDataKey;
+import org.apache.hadoop.ozone.om.helpers.OmCompletedRequestInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a notification strategy to generate events according to S3
+ * notification semantics.
+ */
+public class S3EventNotificationStrategy implements 
OMEventListenerNotificationStrategy {
+  public static final Logger LOG = 
LoggerFactory.getLogger(S3EventNotificationStrategy.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+
+  @Override
+  public List<String> determineEventsForOperation(OmCompletedRequestInfo 
requestInfo) {
+
+    switch (requestInfo.getCmdType()) {
+    case CreateKey:
+    case CommitKey:
+      return Collections.singletonList(createS3Event("ObjectCreated:Put",
+              requestInfo.getVolumeName(),
+              requestInfo.getBucketName(),
+              requestInfo.getKeyName(),
+              Collections.emptyMap())
+      );
+    case CreateFile:
+      OmCompletedRequestInfo.OperationArgs.CreateFileArgs createFileArgs
+          = (OmCompletedRequestInfo.OperationArgs.CreateFileArgs) 
requestInfo.getOpArgs();
+
+      // XXX: ozoneEventData is an Ozone extension. Its is unclear if this
+      // schema makes sense but the general S3 schema is somewhat
+      // freeform.  These arguments are more informational than

Review Comment:
   Typo in comment: "Its is unclear" should be "It is unclear".



##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/s3/S3EventNotification.java:
##########
@@ -0,0 +1,671 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.eventlistener.s3;
+
+/* copy of
+ * software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification
+ * class taken from AWS SDK (1.x) with minor changes for build issues
+ * and removed usage of unnecessary AWS specific extension entiies:

Review Comment:
   Typo in comment: "entiies" should be "entities".
   



##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/s3/S3EventNotificationBuilder.java:
##########
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.eventlistener.s3;
+
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.S3BucketEntity;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.S3EventNotificationRecord;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.S3ObjectEntity;
+import 
org.apache.hadoop.ozone.om.eventlistener.s3.S3EventNotification.UserIdentityEntity;
+
+/**
+ * This is a builder for the AWS event notification class
+ * com.amazonaws.services.s3.event.S3EventNotification which is part of
+ * AWS SDK 1.x
+ *
+ * NOTE: the above class is designed for deserialization which is why it
+ * requires this builder wrapper.
+ *
+ * XXX: we may need to fork these classes so that we can customize it to
+ * our needs.
+ */
+public class S3EventNotificationBuilder {
+
+  private static final String REGION = "us-east-1";
+  //private static final String BUCKET_ARN_PREFIX = "arn:aws:s3:" + REGION;
+  private static final String EVENT_SOURCE = "ozone:s3";
+  private static final String EVENT_VERSION = "2.1";
+  private static final String USER_IDENTITY = "some-principalId";
+
+  private static final String SCHEMA_VERSION = "1.0";
+  private static final String CONFIGURATION_ID = "mynotif1";
+
+  private final String objectKey;
+  private final String bucketName;
+  private final String bucketArn;
+  private final String eventName;
+  private final Instant eventTime;
+  private final String etag;
+  private final Map<String, Object> ozoneEventData;
+
+  // mutable fields defaulting to null
+  private Long objectSize;
+  private String objectVersionId;
+  private String objectSequencer;
+
+  public S3EventNotificationBuilder(String objectKey,
+                                    String bucketName,
+                                    String bucketArn,
+                                    String eventName,
+                                    Instant eventTime,
+                                    String etag) {
+    this.objectKey = objectKey;
+    this.bucketName = bucketName;
+    this.bucketArn = bucketArn;
+    this.eventName = eventName;
+    this.eventTime = eventTime;
+    this.etag = etag;
+    this.ozoneEventData = new HashMap<>();
+  }
+
+  public S3EventNotificationBuilder setObjectSize(long objectSize) {
+    this.objectSize = objectSize;
+    return this;
+  }
+
+  public S3EventNotificationBuilder setObjectVersionId(String objectVersionId) 
{
+    this.objectVersionId = objectVersionId;
+    return this;
+  }
+
+  public S3EventNotificationBuilder setObjectSequencer(String objectSequencer) 
{
+    this.objectSequencer = objectSequencer;
+    return this;
+  }
+
+  public S3EventNotificationBuilder addAllEventData(Map<String, Object> 
ozoneEventDataToAdd) {
+    this.ozoneEventData.putAll(ozoneEventDataToAdd);
+    return this;
+  }
+
+  public S3EventNotification build() {
+    UserIdentityEntity userIdentity = new UserIdentityEntity(USER_IDENTITY);
+    S3BucketEntity s3BucketEntity = new S3BucketEntity(bucketName, 
userIdentity, bucketArn);
+
+    S3EventNotification.S3ObjectEntity s3ObjectEntity = new S3ObjectEntity(
+        objectKey,
+        objectSize,
+        etag,
+        objectVersionId,
+        objectSequencer);
+
+    S3EventNotification.S3Entity s3Entity = new S3EventNotification.S3Entity(
+        CONFIGURATION_ID,
+        s3BucketEntity,
+        s3ObjectEntity,
+        SCHEMA_VERSION);
+
+    S3EventNotificationRecord eventRecord = new S3EventNotificationRecord(
+        REGION,
+        eventName,
+        EVENT_SOURCE,
+        eventTime.toString(),
+        EVENT_VERSION,
+        new S3EventNotification.RequestParametersEntity(""),
+        new S3EventNotification.ResponseElementsEntity("", ""),
+        s3Entity,
+        new S3EventNotification.UserIdentityEntity("tester"),

Review Comment:
   The record's `userIdentity` is hard-coded to "tester" even though a 
USER_IDENTITY constant (and a `userIdentity` object) already exists. This looks 
like leftover test data and makes produced events misleading; consider wiring 
through a real principal (or omit/leave null) and avoid hard-coded values in 
production payloads.
   



##########
hadoop-ozone/ozone-manager-plugins/src/main/java/org/apache/hadoop/ozone/om/eventlistener/s3/S3EventNotification.java:
##########
@@ -0,0 +1,671 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.eventlistener.s3;
+
+/* copy of
+ * software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification
+ * class taken from AWS SDK (1.x) with minor changes for build issues
+ * and removed usage of unnecessary AWS specific extension entiies:

Review Comment:
   This header comment is internally inconsistent: it references 
`software.amazon.awssdk...` (AWS SDK v2) but then says "taken from AWS SDK 
(1.x)", and it also contains a typo ("entiies"). Please correct the SDK version 
reference and fix the spelling so future maintenance and license audits are 
clearer.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to