diff --git a/.brazil.json b/.brazil.json index e554078b10e0..544e62198ed2 100644 --- a/.brazil.json +++ b/.brazil.json @@ -27,6 +27,7 @@ "protocol-core": { "packageName": "AwsJavaSdk-Core-ProtocolCore" }, "regions": { "packageName": "AwsJavaSdk-Core-Regions" }, "s3-transfer-manager": { "packageName": "AwsJavaSdk-S3-TransferManager" }, + "s3-event-notifications": { "packageName": "AwsJavaSdk-S3-EventNotifications" }, "sdk-core": { "packageName": "AwsJavaSdk-Core" }, "url-connection-client": { "packageName": "AwsJavaSdk-HttpClient-UrlConnectionClient" }, "utils": { "packageName": "AwsJavaSdk-Core-Utils" }, diff --git a/.changes/next-release/feature-AWSSDKforJavav2-10ff57d.json b/.changes/next-release/feature-AWSSDKforJavav2-10ff57d.json new file mode 100644 index 000000000000..15811c8ac2f1 --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav2-10ff57d.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Add the model for S3 Event Notifications and json parsers for them" +} diff --git a/aws-sdk-java/pom.xml b/aws-sdk-java/pom.xml index 496aa81db0ff..715f34fccf9d 100644 --- a/aws-sdk-java/pom.xml +++ b/aws-sdk-java/pom.xml @@ -743,6 +743,11 @@ Amazon AutoScaling, etc). s3-transfer-manager ${awsjavasdk.version} + + software.amazon.awssdk + s3-event-notifications + ${awsjavasdk.version} + software.amazon.awssdk sagemaker diff --git a/bom/pom.xml b/bom/pom.xml index 9efcc706d90c..4f54dcbe19bc 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -202,6 +202,11 @@ s3-transfer-manager ${awsjavasdk.version} + + software.amazon.awssdk + s3-event-notifications + ${awsjavasdk.version} + software.amazon.awssdk aws-crt-client diff --git a/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonWriter.java b/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonWriter.java index a7b6a89d0e9f..b3f57dab57ed 100644 --- a/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonWriter.java +++ b/core/json-utils/src/main/java/software/amazon/awssdk/protocols/jsoncore/JsonWriter.java @@ -70,7 +70,7 @@ public JsonWriter writeEndArray() { } public JsonWriter writeNull() { - return unsafeWrite(generator::writeEndArray); + return unsafeWrite(generator::writeNull); } public JsonWriter writeStartObject() { diff --git a/pom.xml b/pom.xml index 30da875338a4..e50798445bc3 100644 --- a/pom.xml +++ b/pom.xml @@ -657,6 +657,7 @@ dynamodb-enhanced s3-transfer-manager iam-policy-builder + s3-event-notifications s3 diff --git a/services-custom/pom.xml b/services-custom/pom.xml index 8f60359ca199..d32574877fda 100644 --- a/services-custom/pom.xml +++ b/services-custom/pom.xml @@ -31,6 +31,7 @@ dynamodb-enhanced s3-transfer-manager iam-policy-builder + s3-event-notifications diff --git a/services-custom/s3-event-notifications/README.md b/services-custom/s3-event-notifications/README.md new file mode 100644 index 000000000000..1a5ece2fce2e --- /dev/null +++ b/services-custom/s3-event-notifications/README.md @@ -0,0 +1,36 @@ +# S3 Event Notifications + +## Overview + +This module contains the classes used to represent Amazon S3 Event Notifications. + + +## Deserialization + +To convert a json notification to java classes, use the static methods +available on `S3EventNotification`: + +```java +String json = "..."; // the notification as json +S3EventNotification event = S3EventNotification.fromJson(json); +event.getRecords().forEach(rec -> println(rec.toString())); +``` + +Any missing fields of the json will be null in the resulting object. +Any extra fields will be ignored. + + +## Serialization + +To convert an instance of `S3EventNotification` to json, use the `.toJson()` +or `toJsonPretty()` method: + +```java +S3EventNotification event = new S3EventNotification(...); +String json = event.toJson(); +String jsonPretty = event.toJsonPretty(); +``` + +`GlacierEventData`, `ReplicationEventData`, `IntelligentTieringEventData` and `LifecycleEventData` +will be excluded from the json if null. Any other null fields of the object will be +serialized in the json as `null`. diff --git a/services-custom/s3-event-notifications/pom.xml b/services-custom/s3-event-notifications/pom.xml new file mode 100644 index 000000000000..77ee75b5e040 --- /dev/null +++ b/services-custom/s3-event-notifications/pom.xml @@ -0,0 +1,111 @@ + + + + + 4.0.0 + + software.amazon.awssdk + aws-sdk-java-pom + 2.25.11-SNAPSHOT + ../../pom.xml + + s3-event-notifications + AWS Java SDK :: S3 :: Event Notification + + The AWS SDK for Java - S3 Even Notification contains POJO classes and utils method to help serialize and + deserialize Amazon S3 Event Notifications. + + + + 1.8 + ${project.parent.version} + + + + + + software.amazon.awssdk + bom-internal + ${awsjavasdk.version} + pom + import + + + + + + + software.amazon.awssdk + third-party-jackson-core + ${awsjavasdk.version} + + + software.amazon.awssdk + json-utils + ${awsjavasdk.version} + + + software.amazon.awssdk + annotations + ${awsjavasdk.version} + + + software.amazon.awssdk + utils + ${awsjavasdk.version} + + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.assertj + assertj-core + test + + + nl.jqno.equalsverifier + equalsverifier + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + software.amazon.awssdk.eventnotifications.s3 + + + + + + + + \ No newline at end of file diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/DefaultS3EventNotificationReader.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/DefaultS3EventNotificationReader.java new file mode 100644 index 000000000000..948a010eaa9e --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/DefaultS3EventNotificationReader.java @@ -0,0 +1,311 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.internal; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.eventnotifications.s3.model.GlacierEventData; +import software.amazon.awssdk.eventnotifications.s3.model.IntelligentTieringEventData; +import software.amazon.awssdk.eventnotifications.s3.model.LifecycleEventData; +import software.amazon.awssdk.eventnotifications.s3.model.ReplicationEventData; +import software.amazon.awssdk.eventnotifications.s3.model.RequestParameters; +import software.amazon.awssdk.eventnotifications.s3.model.ResponseElements; +import software.amazon.awssdk.eventnotifications.s3.model.RestoreEventData; +import software.amazon.awssdk.eventnotifications.s3.model.S3; +import software.amazon.awssdk.eventnotifications.s3.model.S3Bucket; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotificationRecord; +import software.amazon.awssdk.eventnotifications.s3.model.S3Object; +import software.amazon.awssdk.eventnotifications.s3.model.TransitionEventData; +import software.amazon.awssdk.eventnotifications.s3.model.UserIdentity; +import software.amazon.awssdk.protocols.jsoncore.JsonNode; +import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; +import software.amazon.awssdk.utils.Validate; + +@SdkInternalApi +public final class DefaultS3EventNotificationReader implements S3EventNotificationReader { + private static final JsonNodeParser JSON_NODE_PARSER = JsonNodeParser.create(); + + @Override + public S3EventNotification read(String event) { + return read(event.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public S3EventNotification read(byte[] event) { + return read(new ByteArrayInputStream(event)); + } + + @Override + public S3EventNotification read(InputStream event) { + return readEvent(JSON_NODE_PARSER.parse(event)); + } + + private S3EventNotification readEvent(JsonNode jsonNode) { + Map records = expectObjectOrNull(jsonNode, "Records"); + if (records == null) { + return new S3EventNotification(null); + } + return new S3EventNotification(readRecords(records.get("Records"))); + } + + private List readRecords(JsonNode node) { + if (node == null || node.isNull()) { + return null; + } + List recordArray = expectArrayOrNull(node, "Records"); + if (recordArray == null) { + return Collections.emptyList(); + } + return recordArray.stream().map(this::readEventNotificationRecord).collect(Collectors.toList()); + } + + private S3EventNotificationRecord readEventNotificationRecord(JsonNode jsonNode) { + Map recordNode = expectObjectOrNull(jsonNode, "Records[]"); + if (recordNode == null) { + return null; + } + + S3EventNotificationRecord eventNotificationRecord = new S3EventNotificationRecord(); + + String eventVersion = expectStringOrNull(recordNode, "eventVersion"); + eventNotificationRecord.setEventVersion(eventVersion); + + String awsRegion = expectStringOrNull(recordNode, "awsRegion"); + eventNotificationRecord.setAwsRegion(awsRegion); + + String eventName = expectStringOrNull(recordNode, "eventName"); + eventNotificationRecord.setEventName(eventName); + + String eventSource = expectStringOrNull(recordNode, "eventSource"); + eventNotificationRecord.setEventSource(eventSource); + + String eventTime = expectStringOrNull(recordNode, "eventTime"); + eventNotificationRecord.setEventTime(eventName != null ? Instant.parse(eventTime) : null); + + RequestParameters requestParameters = readRequestParameters(recordNode.get("requestParameters")); + eventNotificationRecord.setRequestParameters(requestParameters); + + ResponseElements responseElements = readResponseElements(recordNode.get("responseElements")); + eventNotificationRecord.setResponseElements(responseElements); + + S3 s3 = readS3(recordNode.get("s3")); + eventNotificationRecord.setS3(s3); + + UserIdentity userIdentity = readUserIdentity(recordNode.get("userIdentity")); + eventNotificationRecord.setUserIdentity(userIdentity); + + GlacierEventData glacierEventData = readGlacierEventData(recordNode.get("glacierEventData")); + eventNotificationRecord.setGlacierEventData(glacierEventData); + + + LifecycleEventData lifecycleEventData = readLifecycleEventData(recordNode.get("lifecycleEventData")); + eventNotificationRecord.setLifecycleEventData(lifecycleEventData); + + IntelligentTieringEventData intelligentTieringEventData = + readIntelligentTieringEventData(recordNode.get("intelligentTieringEventData")); + eventNotificationRecord.setIntelligentTieringEventData(intelligentTieringEventData); + + ReplicationEventData replicationEventData = readReplicationEventData(recordNode.get("replicationEventData")); + eventNotificationRecord.setReplicationEventData(replicationEventData); + + return eventNotificationRecord; + } + + private ReplicationEventData readReplicationEventData(JsonNode jsonNode) { + Map replicationDataNode = expectObjectOrNull(jsonNode, "replicationEventData"); + if (replicationDataNode == null) { + return null; + } + + String replicationRuleId = expectStringOrNull(replicationDataNode, "replicationRuleId"); + String destinationBucket = expectStringOrNull(replicationDataNode, "destinationBucket"); + String s3Operation = expectStringOrNull(replicationDataNode, "s3Operation"); + String requestTime = expectStringOrNull(replicationDataNode, "requestTime"); + String failureReason = expectStringOrNull(replicationDataNode, "failureReason"); + String threshold = expectStringOrNull(replicationDataNode, "threshold"); + String replicationTime = expectStringOrNull(replicationDataNode, "replicationTime"); + + return new ReplicationEventData(replicationRuleId, + destinationBucket, + s3Operation, + requestTime, + failureReason, + threshold, + replicationTime); + } + + private IntelligentTieringEventData readIntelligentTieringEventData(JsonNode jsonNode) { + Map lifeCycleEventDataNode = expectObjectOrNull(jsonNode, "intelligentTieringEventData"); + if (lifeCycleEventDataNode == null) { + return null; + } + String destinationAccessTier = expectStringOrNull(lifeCycleEventDataNode, "destinationAccessTier"); + return new IntelligentTieringEventData(destinationAccessTier); + } + + private LifecycleEventData readLifecycleEventData(JsonNode jsonNode) { + Map lifeCycleEventDataNode = expectObjectOrNull(jsonNode, "lifecycleEventData"); + if (lifeCycleEventDataNode == null) { + return null; + } + Map transitionEventDataNode = + expectObjectOrNull(lifeCycleEventDataNode.get("transitionEventData"), "transitionEventData"); + if (transitionEventDataNode == null) { + return new LifecycleEventData(null); + } + String destinationStorageClass = + expectStringOrNull(transitionEventDataNode, "destinationStorageClass"); + return new LifecycleEventData(new TransitionEventData(destinationStorageClass)); + } + + private GlacierEventData readGlacierEventData(JsonNode jsonNode) { + Map glacierEventDataNode = expectObjectOrNull(jsonNode, "glacierEventData"); + if (glacierEventDataNode == null) { + return null; + } + Map restoreEventDataNode = + expectObjectOrNull(glacierEventDataNode.get("restoreEventData"), "restoreEventData"); + if (restoreEventDataNode == null) { + return new GlacierEventData(null); + } + String lifecycleRestorationExpiryTime = expectStringOrNull(restoreEventDataNode, "lifecycleRestorationExpiryTime"); + String lifecycleRestoreStorageClass = expectStringOrNull(restoreEventDataNode, "lifecycleRestoreStorageClass"); + return new GlacierEventData(new RestoreEventData(lifecycleRestorationExpiryTime, + lifecycleRestoreStorageClass)); + } + + private UserIdentity readUserIdentity(JsonNode jsonNode) { + Map userIdentityNode = expectObjectOrNull(jsonNode, "userIdentity"); + if (userIdentityNode == null) { + return null; + } + String principalId = expectStringOrNull(userIdentityNode, "principalId"); + return new UserIdentity(principalId); + } + + private S3 readS3(JsonNode jsonNode) { + Map s3 = expectObjectOrNull(jsonNode, "s3"); + if (s3 == null) { + return null; + } + String configurationId = expectStringOrNull(s3, "configurationId"); + S3Bucket bucket = readBucket(s3.get("bucket")); + S3Object object = readObject(s3.get("object")); + String s3SchemaVersion = expectStringOrNull(s3, "s3SchemaVersion"); + return new S3(configurationId, bucket, object, s3SchemaVersion); + } + + private S3Object readObject(JsonNode jsonNode) { + Map objectNode = expectObjectOrNull(jsonNode, "object"); + if (objectNode == null) { + return null; + } + String key = expectStringOrNull(objectNode, "key"); + Long size = expectLong(objectNode.get("size"), "size"); + String eTag = expectStringOrNull(objectNode, "eTag"); + String versionId = expectStringOrNull(objectNode, "versionId"); + String sequencer = expectStringOrNull(objectNode, "sequencer"); + return new S3Object(key, size, eTag, versionId, sequencer); + } + + private S3Bucket readBucket(JsonNode jsonNode) { + Map bucketNode = expectObjectOrNull(jsonNode, "bucket"); + if (bucketNode == null) { + return null; + } + String name = expectStringOrNull(bucketNode, "name"); + UserIdentity ownerIdentity = readOwnerIdentity(bucketNode.get("ownerIdentity")); + String arn = expectStringOrNull(bucketNode, "arn"); + return new S3Bucket(name, ownerIdentity, arn); + } + + private UserIdentity readOwnerIdentity(JsonNode jsonNode) { + Map ownerIdentityNode = expectObjectOrNull(jsonNode, "ownerIdentity"); + if (ownerIdentityNode == null) { + return null; + } + String principalId = expectStringOrNull(ownerIdentityNode, "principalId"); + return new UserIdentity(principalId); + } + + private ResponseElements readResponseElements(JsonNode jsonNode) { + Map responseElementNode = expectObjectOrNull(jsonNode, "responseElements"); + if (responseElementNode == null) { + return null; + } + String requestId = expectStringOrNull(responseElementNode, "x-amz-request-id"); + String id2 = expectStringOrNull(responseElementNode, "x-amz-id-2"); + return new ResponseElements(id2, requestId); + } + + private RequestParameters readRequestParameters(JsonNode jsonNode) { + Map requestParametersNode = expectObjectOrNull(jsonNode, "requestParameters"); + if (requestParametersNode == null) { + return null; + } + String sourceIpAddressString = expectStringOrNull(requestParametersNode, "sourceIPAddress"); + return new RequestParameters(sourceIpAddressString); + } + + + private String expectStringOrNull(Map node, String name) { + return expectStringOrNull(node.get(name), name); + } + + private String expectStringOrNull(JsonNode node, String name) { + if (node == null) { + return null; + } + Validate.isTrue(node.isString(), "'%s' was not a string", name); + return node.asString(); + } + + private List expectArrayOrNull(JsonNode node, String name) { + if (node == null) { + return null; + } + Validate.isTrue(node.isArray(), "expected '%s' to be an array, but was not.", name); + return node.asArray(); + } + + private Map expectObjectOrNull(JsonNode node, String name) { + if (node == null) { + return null; + } + return expectObject(node, name); + } + + private Map expectObject(JsonNode node, String name) { + Validate.isTrue(node.isObject(), "expected '%s' to be an object, but was not.", name); + return node.asObject(); + } + + private Long expectLong(JsonNode node, String name) { + if (node == null) { + return null; + } + Validate.isTrue(node.isNumber(), "expected '%s' to be numeric, but was not", name); + return Long.parseLong(node.asNumber()); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/DefaultS3EventNotificationWriter.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/DefaultS3EventNotificationWriter.java new file mode 100644 index 000000000000..0ebfdb8bb0d6 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/DefaultS3EventNotificationWriter.java @@ -0,0 +1,304 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.internal; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.util.List; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.eventnotifications.s3.model.GlacierEventData; +import software.amazon.awssdk.eventnotifications.s3.model.IntelligentTieringEventData; +import software.amazon.awssdk.eventnotifications.s3.model.LifecycleEventData; +import software.amazon.awssdk.eventnotifications.s3.model.ReplicationEventData; +import software.amazon.awssdk.eventnotifications.s3.model.RequestParameters; +import software.amazon.awssdk.eventnotifications.s3.model.ResponseElements; +import software.amazon.awssdk.eventnotifications.s3.model.RestoreEventData; +import software.amazon.awssdk.eventnotifications.s3.model.S3; +import software.amazon.awssdk.eventnotifications.s3.model.S3Bucket; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotificationRecord; +import software.amazon.awssdk.eventnotifications.s3.model.S3Object; +import software.amazon.awssdk.eventnotifications.s3.model.TransitionEventData; +import software.amazon.awssdk.eventnotifications.s3.model.UserIdentity; +import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser; +import software.amazon.awssdk.protocols.jsoncore.JsonWriter; +import software.amazon.awssdk.protocols.jsoncore.JsonWriter.JsonGeneratorFactory; +import software.amazon.awssdk.thirdparty.jackson.core.JsonGenerator; + +@SdkInternalApi +public final class DefaultS3EventNotificationWriter implements S3EventNotificationWriter { + private static final S3EventNotificationWriter INSTANCE = S3EventNotificationWriter.builder().build(); + + private final Boolean prettyPrint; + private final JsonGeneratorFactory jsonGeneratorFactory; + + private DefaultS3EventNotificationWriter(DefaultBuilder builder) { + this.prettyPrint = builder.prettyPrint; + if (Boolean.TRUE.equals(builder.prettyPrint)) { + this.jsonGeneratorFactory = os -> { + JsonGenerator generator = JsonNodeParser.DEFAULT_JSON_FACTORY.createGenerator(os); + generator.useDefaultPrettyPrinter(); + return generator; + }; + } else { + this.jsonGeneratorFactory = null; + } + } + + @Override + public String writeToString(S3EventNotification event) { + return new String(writeEvent(event), StandardCharsets.UTF_8); + } + + private byte[] writeEvent(S3EventNotification event) { + JsonWriter writer = JsonWriter.builder() + .jsonGeneratorFactory(jsonGeneratorFactory) + .build(); + writer.writeStartObject(); + writeRecords(writer, event.getRecords()); + writer.writeEndObject(); + return writer.getBytes(); + } + + private void writeRecords(JsonWriter writer, List records) { + writer.writeFieldName("Records"); + if (records == null) { + writer.writeNull(); + return; + } + writer.writeStartArray(); + records.forEach(rec -> writeRecord(writer, rec)); + writer.writeEndArray(); + } + + private void writeRecord(JsonWriter writer, S3EventNotificationRecord rec) { + if (rec == null) { + writer.writeNull(); + return; + } + writer.writeStartObject(); + writeStringField(writer, "eventVersion", rec.getEventVersion()); + writeStringField(writer, "eventSource", rec.getEventSource()); + writeStringField(writer, "awsRegion", rec.getAwsRegion()); + String eventTime = rec.getEventTime() != null + ? DateTimeFormatter.ISO_INSTANT.format(rec.getEventTime()) + : null; + writeStringField(writer, "eventTime", eventTime); + writeStringField(writer, "eventName", rec.getEventName()); + writeUserIdentity(writer, rec.getUserIdentity()); + writeRequestParam(writer, rec.getRequestParameters()); + writeResponseElements(writer, rec.getResponseElements()); + writeS3(writer, rec.getS3()); + + if (rec.getGlacierEventData() != null) { + writeGlacierEventData(writer, rec.getGlacierEventData()); + } + + if (rec.getReplicationEventData() != null) { + writeReplicationEventData(writer, rec.getReplicationEventData()); + } + + if (rec.getIntelligentTieringEventData() != null) { + writeIntelligentTieringEventData(writer, rec.getIntelligentTieringEventData()); + } + + if (rec.getLifecycleEventData() != null) { + writeLifecyleEventData(writer, rec.getLifecycleEventData()); + } + + writer.writeEndObject(); + } + + private void writeLifecyleEventData(JsonWriter writer, LifecycleEventData lifecycleEventData) { + writer.writeFieldName("lifecycleEventData"); + writer.writeStartObject(); + TransitionEventData transitionEventData = lifecycleEventData.getTransitionEventData(); + if (transitionEventData != null) { + writer.writeFieldName("transitionEventData"); + writer.writeStartObject(); + writeStringField(writer, "destinationStorageClass", transitionEventData.getDestinationStorageClass()); + writer.writeEndObject(); + } + writer.writeEndObject(); + } + + private void writeIntelligentTieringEventData(JsonWriter writer, IntelligentTieringEventData intelligentTieringEventData) { + writer.writeFieldName("intelligentTieringEventData"); + writer.writeStartObject(); + writeStringField(writer, "destinationAccessTier", intelligentTieringEventData.getDestinationAccessTier()); + writer.writeEndObject(); + } + + private void writeReplicationEventData(JsonWriter writer, ReplicationEventData replicationEventData) { + writer.writeFieldName("replicationEventData"); + writer.writeStartObject(); + writeStringField(writer, "replicationRuleId", replicationEventData.getReplicationRuleId()); + writeStringField(writer, "destinationBucket", replicationEventData.getDestinationBucket()); + writeStringField(writer, "s3Operation", replicationEventData.getS3Operation()); + writeStringField(writer, "requestTime", replicationEventData.getRequestTime()); + writeStringField(writer, "failureReason", replicationEventData.getFailureReason()); + writeStringField(writer, "threshold", replicationEventData.getThreshold()); + writeStringField(writer, "replicationTime", replicationEventData.getReplicationTime()); + writer.writeEndObject(); + } + + private void writeGlacierEventData(JsonWriter writer, GlacierEventData glacierEventData) { + writer.writeFieldName("glacierEventData"); + writer.writeStartObject(); + RestoreEventData restoreEventData = glacierEventData.getRestoreEventData(); + if (restoreEventData != null) { + writer.writeFieldName("restoreEventData"); + writer.writeStartObject(); + Instant lifecycleRestorationExpiryTime = restoreEventData.getLifecycleRestorationExpiryTime(); + String expiryTime = lifecycleRestorationExpiryTime == null + ? null + : DateTimeFormatter.ISO_INSTANT.format(lifecycleRestorationExpiryTime); + writeStringField(writer, "lifecycleRestorationExpiryTime", expiryTime); + writeStringField(writer, "lifecycleRestoreStorageClass", restoreEventData.getLifecycleRestoreStorageClass()); + } + writer.writeEndObject(); + writer.writeEndObject(); + } + + private void writeS3(JsonWriter writer, S3 s3) { + writer.writeFieldName("s3"); + if (s3 == null) { + writer.writeNull(); + return; + } + writer.writeStartObject(); + writeStringField(writer, "s3SchemaVersion", s3.getS3SchemaVersion()); + writeStringField(writer, "configurationId", s3.getConfigurationId()); + writeS3Bucket(writer, s3.getBucket()); + writeS3Object(writer, s3.getObject()); + writer.writeEndObject(); + } + + private void writeS3Object(JsonWriter writer, S3Object s3Object) { + writer.writeFieldName("object"); + if (s3Object == null) { + writer.writeNull(); + return; + } + writer.writeStartObject(); + writeStringField(writer, "key", s3Object.getKey()); + writeNumericField(writer, "size", s3Object.getSizeAsLong()); + writeStringField(writer, "eTag", s3Object.getETag()); + writeStringField(writer, "versionId", s3Object.getVersionId()); + writeStringField(writer, "sequencer", s3Object.getSequencer()); + writer.writeEndObject(); + } + + private void writeS3Bucket(JsonWriter writer, S3Bucket bucket) { + writer.writeFieldName("bucket"); + if (bucket == null) { + writer.writeNull(); + return; + } + writer.writeStartObject(); + writeStringField(writer, "name", bucket.getName()); + writer.writeFieldName("ownerIdentity"); + if (bucket.getOwnerIdentity().getPrincipalId() == null) { + writer.writeNull(); + } else { + writer.writeStartObject(); + writeStringField(writer, "principalId", bucket.getOwnerIdentity().getPrincipalId()); + writer.writeEndObject(); + } + writeStringField(writer, "arn", bucket.getArn()); + writer.writeEndObject(); + } + + private void writeResponseElements(JsonWriter writer, ResponseElements responseElements) { + writer.writeFieldName("responseElements"); + if (responseElements == null) { + writer.writeNull(); + return; + } + writer.writeStartObject(); + writeStringField(writer, "x-amz-request-id", responseElements.getXAmzRequestId()); + writeStringField(writer, "x-amz-id-2", responseElements.getXAmzId2()); + writer.writeEndObject(); + } + + private void writeRequestParam(JsonWriter writer, RequestParameters requestParameters) { + writer.writeFieldName("requestParameters"); + if (requestParameters == null) { + writer.writeNull(); + return; + } + writer.writeStartObject(); + writeStringField(writer, "sourceIPAddress", requestParameters.getSourceIpAddress()); + writer.writeEndObject(); + } + + private void writeUserIdentity(JsonWriter writer, UserIdentity userIdentity) { + writer.writeFieldName("userIdentity"); + if (userIdentity == null) { + writer.writeNull(); + return; + } + writer.writeStartObject(); + writeStringField(writer, "principalId", userIdentity.getPrincipalId()); + writer.writeEndObject(); + } + + public static S3EventNotificationWriter create() { + return INSTANCE; + } + + private void writeStringField(JsonWriter writer, String field, String value) { + writer.writeFieldName(field); + writer.writeValue(value); + } + + private void writeNumericField(JsonWriter writer, String field, Long value) { + writer.writeFieldName(field); + writer.writeNumber(value.toString()); + } + + @Override + public DefaultBuilder toBuilder() { + return new DefaultBuilder(this); + } + + public static S3EventNotificationWriter.Builder builder() { + return new DefaultBuilder(); + } + + public static final class DefaultBuilder implements S3EventNotificationWriter.Builder { + private Boolean prettyPrint; + + private DefaultBuilder() { + } + + private DefaultBuilder(DefaultS3EventNotificationWriter writer) { + this.prettyPrint = writer.prettyPrint; + } + + @Override + public S3EventNotificationWriter.Builder prettyPrint(Boolean prettyPrint) { + this.prettyPrint = prettyPrint; + return this; + } + + @Override + public S3EventNotificationWriter build() { + return new DefaultS3EventNotificationWriter(this); + } + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/S3EventNotificationReader.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/S3EventNotificationReader.java new file mode 100644 index 000000000000..f2699babb08a --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/S3EventNotificationReader.java @@ -0,0 +1,66 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.internal; + +import java.io.InputStream; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification; +import software.amazon.awssdk.thirdparty.jackson.core.JsonParseException; + +/** + * Read Amazon S3 Event Notification in json format and marshal them into an instance of {@link S3EventNotification}. + */ +@SdkInternalApi +public interface S3EventNotificationReader { + + /** + * Creates a S3EventNotificationReader + * @return + */ + static S3EventNotificationReader create() { + return new DefaultS3EventNotificationReader(); + } + + /** + * Read a json formatted Amazon S3 Event Notification from a UTF-8 string. + * Will ignores all additional fields and missing fields will be set to null. + * + * @param event UTF-8 json of the notification. + * @return S3EventNotification + * @throws JsonParseException if json if malformed + */ + S3EventNotification read(String event); + + /** + * Read a json formatted Amazon S3 Event Notification from a UTF-8 InputStream. + * Will ignores all additional fields and missing fields will be set to null. + * + * @param event UTF-8 json of the notification. + * @return S3EventNotification + * @throws JsonParseException if json if malformed + */ + S3EventNotification read(InputStream event); + + /** + * Read a json formatted Amazon S3 Event Notification from a UTF-8 encoded byte array. + * Will ignores all additional fields and missing fields will be set to null. + * + * @param event UTF-8 json of the notification. + * @return S3EventNotification + * @throws JsonParseException if json if malformed + */ + S3EventNotification read(byte[] event); +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/S3EventNotificationWriter.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/S3EventNotificationWriter.java new file mode 100644 index 000000000000..8e1cae45a9b9 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/internal/S3EventNotificationWriter.java @@ -0,0 +1,57 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.internal; + +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification; +import software.amazon.awssdk.utils.builder.CopyableBuilder; +import software.amazon.awssdk.utils.builder.ToCopyableBuilder; + +/** + * Converts a {@link S3EventNotification} to json. + */ +@SdkInternalApi +public interface S3EventNotificationWriter + extends ToCopyableBuilder { + + /** + * Write an event to json string. Null field will be included as null. + * + * @param event to event to convert to json. + * @return the json representation of the event. + */ + String writeToString(S3EventNotification event); + + static S3EventNotificationWriter create() { + return DefaultS3EventNotificationWriter.create(); + } + + static Builder builder() { + return DefaultS3EventNotificationWriter.builder(); + } + + interface Builder extends CopyableBuilder { + /** + * Configure whether the writer should "pretty-print" the output. + *

+ * When set to true, this will add new lines and indentation to the output to make it easier for a human to read, at + * the expense of extra data (white space) being output. + *

+ * By default, this is {@code false}. + */ + Builder prettyPrint(Boolean prettyPrint); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/GlacierEventData.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/GlacierEventData.java new file mode 100644 index 000000000000..0a42b47bc8f2 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/GlacierEventData.java @@ -0,0 +1,65 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +/** + * The GlacierEventData is only visible for s3:ObjectRestore:Completed events. + * Contains information related to restoring an archived object. For more information about archive and storage classes, see + * Restoring an archived object + */ +@SdkPublicApi +public class GlacierEventData { + + private final RestoreEventData restoreEventData; + + public GlacierEventData(RestoreEventData restoreEventData) { + this.restoreEventData = restoreEventData; + } + + public RestoreEventData getRestoreEventData() { + return restoreEventData; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GlacierEventData that = (GlacierEventData) o; + + return Objects.equals(restoreEventData, that.restoreEventData); + } + + @Override + public int hashCode() { + return restoreEventData != null ? restoreEventData.hashCode() : 0; + } + + @Override + public String toString() { + return ToString.builder("GlacierEventDataEntity") + .add("restoreEventData", restoreEventData) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/IntelligentTieringEventData.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/IntelligentTieringEventData.java new file mode 100644 index 000000000000..acd12762d53a --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/IntelligentTieringEventData.java @@ -0,0 +1,64 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +/** + * The IntelligentTieringEventData key is only visible for S3 Intelligent-Tiering events. + */ +@SdkPublicApi +public class IntelligentTieringEventData { + + private final String destinationAccessTier; + + public IntelligentTieringEventData(String destinationAccessTier) { + this.destinationAccessTier = destinationAccessTier; + } + + public String getDestinationAccessTier() { + return destinationAccessTier; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + IntelligentTieringEventData that = (IntelligentTieringEventData) o; + + return Objects.equals(destinationAccessTier, that.destinationAccessTier); + } + + @Override + public int hashCode() { + return destinationAccessTier != null ? destinationAccessTier.hashCode() : 0; + } + + @Override + public String toString() { + return ToString.builder("IntelligentTieringEventDataEntity") + .add("destinationAccessTier", destinationAccessTier) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/LifecycleEventData.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/LifecycleEventData.java new file mode 100644 index 000000000000..94f0c77bccde --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/LifecycleEventData.java @@ -0,0 +1,64 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +/** + * The LifecycleEventData is only visible for S3 Lifecycle transition events. + */ +@SdkPublicApi +public class LifecycleEventData { + + private final TransitionEventData transitionEventData; + + public LifecycleEventData(TransitionEventData transitionEventData) { + this.transitionEventData = transitionEventData; + } + + public TransitionEventData getTransitionEventData() { + return transitionEventData; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + LifecycleEventData that = (LifecycleEventData) o; + + return Objects.equals(transitionEventData, that.transitionEventData); + } + + @Override + public int hashCode() { + return transitionEventData != null ? transitionEventData.hashCode() : 0; + } + + @Override + public String toString() { + return ToString.builder("LifecycleEventDataEntity") + .add("transitionEventData", transitionEventData) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/ReplicationEventData.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/ReplicationEventData.java new file mode 100644 index 000000000000..c193f3506ab6 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/ReplicationEventData.java @@ -0,0 +1,138 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +/** + * The ReplicationEventData is only visible for replication events. + */ +@SdkPublicApi +public class ReplicationEventData { + + private final String replicationRuleId; + private final String destinationBucket; + private final String s3Operation; + private final String requestTime; + private final String failureReason; + private final String threshold; + private final String replicationTime; + + public ReplicationEventData( + String replicationRuleId, + String destinationBucket, + String s3Operation, + String requestTime, + String failureReason, + String threshold, + String replicationTime) { + this.replicationRuleId = replicationRuleId; + this.destinationBucket = destinationBucket; + this.s3Operation = s3Operation; + this.requestTime = requestTime; + this.failureReason = failureReason; + this.threshold = threshold; + this.replicationTime = replicationTime; + } + + public String getReplicationRuleId() { + return replicationRuleId; + } + + public String getDestinationBucket() { + return destinationBucket; + } + + public String getS3Operation() { + return s3Operation; + } + + public String getRequestTime() { + return requestTime; + } + + public String getFailureReason() { + return failureReason; + } + + public String getThreshold() { + return threshold; + } + + public String getReplicationTime() { + return replicationTime; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ReplicationEventData that = (ReplicationEventData) o; + + if (!Objects.equals(replicationRuleId, that.replicationRuleId)) { + return false; + } + if (!Objects.equals(destinationBucket, that.destinationBucket)) { + return false; + } + if (!Objects.equals(s3Operation, that.s3Operation)) { + return false; + } + if (!Objects.equals(requestTime, that.requestTime)) { + return false; + } + if (!Objects.equals(failureReason, that.failureReason)) { + return false; + } + if (!Objects.equals(threshold, that.threshold)) { + return false; + } + return Objects.equals(replicationTime, that.replicationTime); + } + + @Override + public int hashCode() { + int result = replicationRuleId != null ? replicationRuleId.hashCode() : 0; + result = 31 * result + (destinationBucket != null ? destinationBucket.hashCode() : 0); + result = 31 * result + (s3Operation != null ? s3Operation.hashCode() : 0); + result = 31 * result + (requestTime != null ? requestTime.hashCode() : 0); + result = 31 * result + (failureReason != null ? failureReason.hashCode() : 0); + result = 31 * result + (threshold != null ? threshold.hashCode() : 0); + result = 31 * result + (replicationTime != null ? replicationTime.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("ReplicationEventData") + .add("replicationRuleId", replicationRuleId) + .add("destinationBucket", destinationBucket) + .add("s3Operation", s3Operation) + .add("requestTime", requestTime) + .add("failureReason", failureReason) + .add("threshold", threshold) + .add("replicationTime", replicationTime) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/RequestParameters.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/RequestParameters.java new file mode 100644 index 000000000000..7bb90f429c50 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/RequestParameters.java @@ -0,0 +1,61 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class RequestParameters { + + private final String sourceIpAddress; + + public RequestParameters(String sourceIpAddress) { + this.sourceIpAddress = sourceIpAddress; + } + + public String getSourceIpAddress() { + return sourceIpAddress; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + RequestParameters that = (RequestParameters) o; + + return Objects.equals(sourceIpAddress, that.sourceIpAddress); + } + + @Override + public int hashCode() { + return sourceIpAddress != null ? sourceIpAddress.hashCode() : 0; + } + + @Override + public String toString() { + return ToString.builder("RequestParameters") + .add("sourceIpAddress", sourceIpAddress) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/ResponseElements.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/ResponseElements.java new file mode 100644 index 000000000000..b7ec0747dd5a --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/ResponseElements.java @@ -0,0 +1,72 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class ResponseElements { + + private final String xAmzId2; + private final String xAmzRequestId; + + public ResponseElements(String xAmzId2, String xAmzRequestId) { + this.xAmzId2 = xAmzId2; + this.xAmzRequestId = xAmzRequestId; + } + + public String getXAmzId2() { + return xAmzId2; + } + + public String getXAmzRequestId() { + return xAmzRequestId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ResponseElements that = (ResponseElements) o; + + if (!Objects.equals(xAmzId2, that.xAmzId2)) { + return false; + } + return Objects.equals(xAmzRequestId, that.xAmzRequestId); + } + + @Override + public int hashCode() { + int result = xAmzId2 != null ? xAmzId2.hashCode() : 0; + result = 31 * result + (xAmzRequestId != null ? xAmzRequestId.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("ResponseElements") + .add("xAmzId2", xAmzId2) + .add("xAmzRequestId", xAmzRequestId) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/RestoreEventData.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/RestoreEventData.java new file mode 100644 index 000000000000..44ff4f595804 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/RestoreEventData.java @@ -0,0 +1,83 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import java.time.Instant; +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +/** + * The RestoreEventData contains attributes that are related to the restore request. + */ +@SdkPublicApi +public class RestoreEventData { + + private final Instant lifecycleRestorationExpiryTime; + private final String lifecycleRestoreStorageClass; + + public RestoreEventData(String lifecycleRestorationExpiryTime, String lifecycleRestoreStorageClass) { + this.lifecycleRestorationExpiryTime = + lifecycleRestorationExpiryTime != null ? Instant.parse(lifecycleRestorationExpiryTime) : null; + this.lifecycleRestoreStorageClass = lifecycleRestoreStorageClass; + } + + /** + * @return The time, in ISO-8601 format, for example, 1970-01-01T00:00:00.000Z, of Restore Expiry. + */ + public Instant getLifecycleRestorationExpiryTime() { + return lifecycleRestorationExpiryTime; + } + + /** + * @return The source storage class for restore. + */ + public String getLifecycleRestoreStorageClass() { + return lifecycleRestoreStorageClass; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + RestoreEventData that = (RestoreEventData) o; + + if (!Objects.equals(lifecycleRestorationExpiryTime, that.lifecycleRestorationExpiryTime)) { + return false; + } + return Objects.equals(lifecycleRestoreStorageClass, that.lifecycleRestoreStorageClass); + } + + @Override + public int hashCode() { + int result = lifecycleRestorationExpiryTime != null ? lifecycleRestorationExpiryTime.hashCode() : 0; + result = 31 * result + (lifecycleRestoreStorageClass != null ? lifecycleRestoreStorageClass.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("RestoreEventData") + .add("lifecycleRestorationExpiryTime", lifecycleRestorationExpiryTime) + .add("lifecycleRestoreStorageClass", lifecycleRestoreStorageClass) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3.java new file mode 100644 index 000000000000..85c6637a9ea1 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3.java @@ -0,0 +1,94 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class S3 { + + private final String configurationId; + private final S3Bucket bucket; + private final S3Object object; + private final String s3SchemaVersion; + + public S3(String configurationId, S3Bucket bucket, S3Object object, String s3SchemaVersion) { + this.configurationId = configurationId; + this.bucket = bucket; + this.object = object; + this.s3SchemaVersion = s3SchemaVersion; + } + + public String getConfigurationId() { + return configurationId; + } + + public S3Bucket getBucket() { + return bucket; + } + + public S3Object getObject() { + return object; + } + + public String getS3SchemaVersion() { + return s3SchemaVersion; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + S3 s3 = (S3) o; + + if (!Objects.equals(configurationId, s3.configurationId)) { + return false; + } + if (!Objects.equals(bucket, s3.bucket)) { + return false; + } + if (!Objects.equals(object, s3.object)) { + return false; + } + return Objects.equals(s3SchemaVersion, s3.s3SchemaVersion); + } + + @Override + public int hashCode() { + int result = configurationId != null ? configurationId.hashCode() : 0; + result = 31 * result + (bucket != null ? bucket.hashCode() : 0); + result = 31 * result + (object != null ? object.hashCode() : 0); + result = 31 * result + (s3SchemaVersion != null ? s3SchemaVersion.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("S3") + .add("configurationId", configurationId) + .add("bucket", bucket) + .add("object", object) + .add("s3SchemaVersion", s3SchemaVersion) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3Bucket.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3Bucket.java new file mode 100644 index 000000000000..6d14c790de4b --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3Bucket.java @@ -0,0 +1,84 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class S3Bucket { + + private final String name; + private final UserIdentity ownerIdentity; + private final String arn; + + public S3Bucket(String name, UserIdentity ownerIdentity, String arn) { + this.name = name; + this.ownerIdentity = ownerIdentity; + this.arn = arn; + } + + public String getName() { + return name; + } + + public UserIdentity getOwnerIdentity() { + return ownerIdentity; + } + + public String getArn() { + return arn; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + S3Bucket s3Bucket = (S3Bucket) o; + + if (!Objects.equals(name, s3Bucket.name)) { + return false; + } + if (!Objects.equals(ownerIdentity, s3Bucket.ownerIdentity)) { + return false; + } + return Objects.equals(arn, s3Bucket.arn); + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (ownerIdentity != null ? ownerIdentity.hashCode() : 0); + result = 31 * result + (arn != null ? arn.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("S3Bucket") + .add("name", name) + .add("ownerIdentity", ownerIdentity) + .add("arn", arn) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotification.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotification.java new file mode 100644 index 000000000000..cc3e36056e54 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotification.java @@ -0,0 +1,92 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + + +import java.io.InputStream; +import java.util.List; +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.eventnotifications.s3.internal.S3EventNotificationReader; +import software.amazon.awssdk.eventnotifications.s3.internal.S3EventNotificationWriter; +import software.amazon.awssdk.utils.ToString; + +/** + * A helper class that represents a strongly typed S3 EventNotification item sent to SQS, SNS, or Lambda. + */ +@SdkPublicApi +public class S3EventNotification { + + private final List records; + + public S3EventNotification(List records) { + this.records = records; + } + + public List getRecords() { + return records; + } + + public static S3EventNotification fromJson(String json) { + return S3EventNotificationReader.create().read(json); + } + + + public static S3EventNotification fromJson(byte[] json) { + return S3EventNotificationReader.create().read(json); + } + + public S3EventNotification fromJson(InputStream json) { + return S3EventNotificationReader.create().read(json); + } + + public String toJson() { + return S3EventNotificationWriter.create().writeToString(this); + } + + public String toJsonPretty() { + S3EventNotificationWriter writer = S3EventNotificationWriter.builder() + .prettyPrint(true) + .build(); + return writer.writeToString(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + S3EventNotification that = (S3EventNotification) o; + + return Objects.equals(records, that.records); + } + + @Override + public int hashCode() { + return records != null ? records.hashCode() : 0; + } + + @Override + public String toString() { + return ToString.builder("S3EventNotification") + .add("records", records) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationRecord.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationRecord.java new file mode 100644 index 000000000000..0636268e8f58 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationRecord.java @@ -0,0 +1,290 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import java.time.Instant; +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.annotations.SdkTestInternalApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class S3EventNotificationRecord { + + private String awsRegion; + private String eventName; + private String eventSource; + private String eventVersion; + private RequestParameters requestParameters; + private ResponseElements responseElements; + private S3 s3; + private UserIdentity userIdentity; + private GlacierEventData glacierEventData; + private LifecycleEventData lifecycleEventData; + private IntelligentTieringEventData intelligentTieringEventData; + private ReplicationEventData replicationEventData; + private Instant eventTime; + + public S3EventNotificationRecord() { + } + + @SdkTestInternalApi + S3EventNotificationRecord( + String awsRegion, + String eventName, + String eventSource, + String eventTime, + String eventVersion, + RequestParameters requestParameters, + ResponseElements responseElements, + S3 s3, + UserIdentity userIdentity) { + this(awsRegion, + eventName, + eventSource, + eventTime, + eventVersion, + requestParameters, + responseElements, + s3, + userIdentity, + null, + null, + null, + null); + } + + @SdkTestInternalApi + S3EventNotificationRecord( + String awsRegion, + String eventName, + String eventSource, + String eventTime, + String eventVersion, + RequestParameters requestParameters, + ResponseElements responseElements, + S3 s3, + UserIdentity userIdentity, + GlacierEventData glacierEventData, + LifecycleEventData lifecycleEventData, + IntelligentTieringEventData intelligentTieringEventData, + ReplicationEventData replicationEventData) { + this.awsRegion = awsRegion; + this.eventName = eventName; + this.eventSource = eventSource; + this.eventTime = eventName != null ? Instant.parse(eventTime) : null; + this.eventVersion = eventVersion; + this.requestParameters = requestParameters; + this.responseElements = responseElements; + this.s3 = s3; + this.userIdentity = userIdentity; + this.glacierEventData = glacierEventData; + this.lifecycleEventData = lifecycleEventData; + this.intelligentTieringEventData = intelligentTieringEventData; + this.replicationEventData = replicationEventData; + } + + public String getAwsRegion() { + return awsRegion; + } + + public String getEventName() { + return eventName; + } + + public String getEventSource() { + return eventSource; + } + + public Instant getEventTime() { + return eventTime; + } + + public String getEventVersion() { + return eventVersion; + } + + public RequestParameters getRequestParameters() { + return requestParameters; + } + + public ResponseElements getResponseElements() { + return responseElements; + } + + public S3 getS3() { + return s3; + } + + public UserIdentity getUserIdentity() { + return userIdentity; + } + + public GlacierEventData getGlacierEventData() { + return glacierEventData; + } + + public LifecycleEventData getLifecycleEventData() { + return lifecycleEventData; + } + + public IntelligentTieringEventData getIntelligentTieringEventData() { + return intelligentTieringEventData; + } + + public ReplicationEventData getReplicationEventData() { + return replicationEventData; + } + + public void setAwsRegion(String awsRegion) { + this.awsRegion = awsRegion; + } + + public void setEventName(String eventName) { + this.eventName = eventName; + } + + public void setEventSource(String eventSource) { + this.eventSource = eventSource; + } + + public void setEventVersion(String eventVersion) { + this.eventVersion = eventVersion; + } + + public void setRequestParameters(RequestParameters requestParameters) { + this.requestParameters = requestParameters; + } + + public void setResponseElements(ResponseElements responseElements) { + this.responseElements = responseElements; + } + + public void setS3(S3 s3) { + this.s3 = s3; + } + + public void setUserIdentity(UserIdentity userIdentity) { + this.userIdentity = userIdentity; + } + + public void setGlacierEventData(GlacierEventData glacierEventData) { + this.glacierEventData = glacierEventData; + } + + public void setLifecycleEventData(LifecycleEventData lifecycleEventData) { + this.lifecycleEventData = lifecycleEventData; + } + + public void setIntelligentTieringEventData(IntelligentTieringEventData intelligentTieringEventData) { + this.intelligentTieringEventData = intelligentTieringEventData; + } + + public void setReplicationEventData(ReplicationEventData replicationEventData) { + this.replicationEventData = replicationEventData; + } + + public void setEventTime(Instant eventTime) { + this.eventTime = eventTime; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + S3EventNotificationRecord that = (S3EventNotificationRecord) o; + + if (!Objects.equals(awsRegion, that.awsRegion)) { + return false; + } + if (!Objects.equals(eventName, that.eventName)) { + return false; + } + if (!Objects.equals(eventSource, that.eventSource)) { + return false; + } + if (!Objects.equals(eventVersion, that.eventVersion)) { + return false; + } + if (!Objects.equals(requestParameters, that.requestParameters)) { + return false; + } + if (!Objects.equals(responseElements, that.responseElements)) { + return false; + } + if (!Objects.equals(s3, that.s3)) { + return false; + } + if (!Objects.equals(userIdentity, that.userIdentity)) { + return false; + } + if (!Objects.equals(glacierEventData, that.glacierEventData)) { + return false; + } + if (!Objects.equals(lifecycleEventData, that.lifecycleEventData)) { + return false; + } + if (!Objects.equals(intelligentTieringEventData, that.intelligentTieringEventData)) { + return false; + } + if (!Objects.equals(replicationEventData, that.replicationEventData)) { + return false; + } + return Objects.equals(eventTime, that.eventTime); + } + + @Override + public int hashCode() { + int result = awsRegion != null ? awsRegion.hashCode() : 0; + result = 31 * result + (eventName != null ? eventName.hashCode() : 0); + result = 31 * result + (eventSource != null ? eventSource.hashCode() : 0); + result = 31 * result + (eventVersion != null ? eventVersion.hashCode() : 0); + result = 31 * result + (requestParameters != null ? requestParameters.hashCode() : 0); + result = 31 * result + (responseElements != null ? responseElements.hashCode() : 0); + result = 31 * result + (s3 != null ? s3.hashCode() : 0); + result = 31 * result + (userIdentity != null ? userIdentity.hashCode() : 0); + result = 31 * result + (glacierEventData != null ? glacierEventData.hashCode() : 0); + result = 31 * result + (lifecycleEventData != null ? lifecycleEventData.hashCode() : 0); + result = 31 * result + (intelligentTieringEventData != null ? intelligentTieringEventData.hashCode() : 0); + result = 31 * result + (replicationEventData != null ? replicationEventData.hashCode() : 0); + result = 31 * result + (eventTime != null ? eventTime.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("S3EventNotificationRecord") + .add("awsRegion", awsRegion) + .add("eventName", eventName) + .add("eventSource", eventSource) + .add("eventVersion", eventVersion) + .add("requestParameters", requestParameters) + .add("responseElements", responseElements) + .add("s3", s3) + .add("userIdentity", userIdentity) + .add("glacierEventData", glacierEventData) + .add("lifecycleEventData", lifecycleEventData) + .add("intelligentTieringEventData", intelligentTieringEventData) + .add("replicationEventData", replicationEventData) + .add("eventTime", eventTime) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3Object.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3Object.java new file mode 100644 index 000000000000..a8ce74f68a87 --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/S3Object.java @@ -0,0 +1,122 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class S3Object { + + private final String key; + private final Long size; + private final String eTag; + private final String versionId; + private final String sequencer; + + public S3Object(String key, Long size, String eTag, String versionId, String sequencer) { + this.key = key; + this.size = size; + this.eTag = eTag; + this.versionId = versionId; + this.sequencer = sequencer; + } + + public String getKey() { + return key; + } + + /** + * S3 URL encodes the key of the object involved in the event. This is a convenience method to automatically URL decode the + * key. + * + * @return The URL decoded object key. + */ + public String getUrlDecodedKey() { + try { + return URLDecoder.decode(getKey(), StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + public Long getSizeAsLong() { + return size; + } + + public String getETag() { + return eTag; + } + + public String getVersionId() { + return versionId; + } + + public String getSequencer() { + return sequencer; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + S3Object s3Object = (S3Object) o; + + if (!Objects.equals(key, s3Object.key)) { + return false; + } + if (!Objects.equals(size, s3Object.size)) { + return false; + } + if (!Objects.equals(eTag, s3Object.eTag)) { + return false; + } + if (!Objects.equals(versionId, s3Object.versionId)) { + return false; + } + return Objects.equals(sequencer, s3Object.sequencer); + } + + @Override + public int hashCode() { + int result = key != null ? key.hashCode() : 0; + result = 31 * result + (size != null ? size.hashCode() : 0); + result = 31 * result + (eTag != null ? eTag.hashCode() : 0); + result = 31 * result + (versionId != null ? versionId.hashCode() : 0); + result = 31 * result + (sequencer != null ? sequencer.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return ToString.builder("S3Object") + .add("key", key) + .add("size", size) + .add("eTag", eTag) + .add("versionId", versionId) + .add("sequencer", sequencer) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/TransitionEventData.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/TransitionEventData.java new file mode 100644 index 000000000000..8255c3cb5fdd --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/TransitionEventData.java @@ -0,0 +1,61 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class TransitionEventData { + + private final String destinationStorageClass; + + public TransitionEventData(String destinationStorageClass) { + this.destinationStorageClass = destinationStorageClass; + } + + public String getDestinationStorageClass() { + return destinationStorageClass; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + TransitionEventData that = (TransitionEventData) o; + + return Objects.equals(destinationStorageClass, that.destinationStorageClass); + } + + @Override + public int hashCode() { + return destinationStorageClass != null ? destinationStorageClass.hashCode() : 0; + } + + @Override + public String toString() { + return ToString.builder("TransitionEventData") + .add("destinationStorageClass", destinationStorageClass) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/UserIdentity.java b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/UserIdentity.java new file mode 100644 index 000000000000..0f132a9cde2d --- /dev/null +++ b/services-custom/s3-event-notifications/src/main/java/software/amazon/awssdk/eventnotifications/s3/model/UserIdentity.java @@ -0,0 +1,60 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.utils.ToString; + +@SdkPublicApi +public class UserIdentity { + + private final String principalId; + + public UserIdentity(String principalId) { + this.principalId = principalId; + } + + public String getPrincipalId() { + return principalId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + UserIdentity that = (UserIdentity) o; + + return Objects.equals(principalId, that.principalId); + } + + @Override + public int hashCode() { + return principalId != null ? principalId.hashCode() : 0; + } + + @Override + public String toString() { + return ToString.builder("UserIdentity") + .add("principalId", principalId) + .build(); + } +} diff --git a/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/internal/EqualsAndHashCodeTest.java b/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/internal/EqualsAndHashCodeTest.java new file mode 100644 index 000000000000..118f2ff38050 --- /dev/null +++ b/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/internal/EqualsAndHashCodeTest.java @@ -0,0 +1,32 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.internal; + +import nl.jqno.equalsverifier.Warning; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +class EqualsAndHashCodeTest { + @Test + void allClasses_equalsHashCode_isCorrect() { + EqualsVerifier + .forPackage("software.amazon.awssdk.eventnotifications.s3.model", true) + .suppress(Warning.NONFINAL_FIELDS) + .usingGetClass() + .verify(); + } +} diff --git a/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationReaderTest.java b/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationReaderTest.java new file mode 100644 index 000000000000..ab5814a8182b --- /dev/null +++ b/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationReaderTest.java @@ -0,0 +1,388 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.eventnotifications.s3.model.GlacierEventData; +import software.amazon.awssdk.eventnotifications.s3.model.IntelligentTieringEventData; +import software.amazon.awssdk.eventnotifications.s3.model.LifecycleEventData; +import software.amazon.awssdk.eventnotifications.s3.model.ReplicationEventData; +import software.amazon.awssdk.eventnotifications.s3.model.RequestParameters; +import software.amazon.awssdk.eventnotifications.s3.model.ResponseElements; +import software.amazon.awssdk.eventnotifications.s3.model.RestoreEventData; +import software.amazon.awssdk.eventnotifications.s3.model.S3; +import software.amazon.awssdk.eventnotifications.s3.model.S3Bucket; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotificationRecord; +import software.amazon.awssdk.eventnotifications.s3.model.S3Object; +import software.amazon.awssdk.eventnotifications.s3.model.TransitionEventData; +import software.amazon.awssdk.eventnotifications.s3.model.UserIdentity; +import software.amazon.awssdk.thirdparty.jackson.core.JsonParseException; + +class S3EventNotificationReaderTest { + + @Test + void givenEventWithoutOptionalFields_whenReadingJson_expectOnlyRequiredFields() { + String eventJson = "{ " + + " \"Records\":[ " + + " { " + + " \"eventVersion\":\"2.1\"," + + " \"eventSource\":\"aws:s3\"," + + " \"awsRegion\":\"us-west-2\"," + + " \"eventTime\":\"1970-01-01T00:00:00.000Z\"," + + " \"eventName\":\"ObjectCreated:Put\"," + + " \"userIdentity\":{ " + + " \"principalId\":\"AIDAJDPLRKLG7UEXAMPLE\"" + + " }," + + " \"requestParameters\":{ " + + " \"sourceIPAddress\":\"127.0.0.1\"" + + " }," + + " \"responseElements\":{ " + + " \"x-amz-request-id\":\"C3D13FE58DE4C810\"," + + " \"x-amz-id-2\":\"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD\"" + + " }," + + " \"s3\":{ " + + " \"s3SchemaVersion\":\"1.0\"," + + " \"configurationId\":\"testConfigRule\"," + + " \"bucket\":{ " + + " \"name\":\"mybucket\"," + + " \"ownerIdentity\":{ " + + " \"principalId\":\"A3NL1KOZZKExample\"" + + " }," + + " \"arn\":\"arn:aws:s3:::mybucket\"" + + " }," + + " \"object\":{ " + + " \"key\":\"HappyFace.jpg\"," + + " \"size\":1024," + + " \"eTag\":\"d41d8cd98f00b204e9800998ecf8427e\"," + + " \"versionId\":\"096fKKXTRTtl3on89fVO.nfljtsv6qko\"," + + " \"sequencer\":\"0055AED6DCD90281E5\"" + + " }" + + " }" + + " }" + + " ]" + + "}"; + + S3EventNotification event = S3EventNotification.fromJson(eventJson); + + assertThat(event.getRecords()).hasSize(1); + + // verify constructors + S3EventNotification expected = new S3EventNotification( + Collections.singletonList(new S3EventNotificationRecord( + "us-west-2", + "ObjectCreated:Put", + "aws:s3", + "1970-01-01T00:00:00.000Z", + "2.1", + new RequestParameters("127.0.0.1"), + new ResponseElements( + "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD", "C3D13FE58DE4C810"), + new S3( + "testConfigRule", + new S3Bucket( + "mybucket", + new UserIdentity("A3NL1KOZZKExample"), + "arn:aws:s3:::mybucket"), + new S3Object( + "HappyFace.jpg", + 1024L, + "d41d8cd98f00b204e9800998ecf8427e", + "096fKKXTRTtl3on89fVO.nfljtsv6qko", + "0055AED6DCD90281E5"), + "1.0" + ), + new UserIdentity("AIDAJDPLRKLG7UEXAMPLE") + )) + ); + assertThat(event).isEqualTo(expected); + + // verify getters + S3EventNotificationRecord rec = event.getRecords().get(0); + assertThat(rec).isNotNull(); + assertThat(rec.getAwsRegion()).isEqualTo("us-west-2"); + assertThat(rec.getEventName()).isEqualTo("ObjectCreated:Put"); + assertThat(rec.getEventTime()).isEqualTo(Instant.parse("1970-01-01T00:00:00.000Z")); + assertThat(rec.getEventVersion()).isEqualTo("2.1"); + + UserIdentity userIdentity = rec.getUserIdentity(); + assertThat(userIdentity).isNotNull(); + assertThat(userIdentity.getPrincipalId()).isEqualTo("AIDAJDPLRKLG7UEXAMPLE"); + + RequestParameters requestParameters = rec.getRequestParameters(); + assertThat(requestParameters).isNotNull(); + assertThat(requestParameters.getSourceIpAddress()).isEqualTo("127.0.0.1"); + + ResponseElements responseElements = rec.getResponseElements(); + assertThat(responseElements).isNotNull(); + assertThat(responseElements.getXAmzRequestId()).isEqualTo("C3D13FE58DE4C810"); + assertThat(responseElements.getXAmzId2()) + .isEqualTo("FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD"); + + S3 s3 = rec.getS3(); + assertThat(s3).isNotNull(); + assertThat(s3.getS3SchemaVersion()).isEqualTo("1.0"); + assertThat(s3.getConfigurationId()).isEqualTo("testConfigRule"); + S3Bucket s3Bucket = s3.getBucket(); + assertThat(s3Bucket).isNotNull(); + assertThat(s3Bucket.getName()).isEqualTo("mybucket"); + assertThat(s3Bucket.getArn()).isEqualTo("arn:aws:s3:::mybucket"); + UserIdentity ownerIdentity = s3Bucket.getOwnerIdentity(); + assertThat(ownerIdentity).isNotNull(); + assertThat(ownerIdentity.getPrincipalId()).isEqualTo("A3NL1KOZZKExample"); + S3Object s3Object = s3.getObject(); + assertThat(s3Object).isNotNull(); + assertThat(s3Object.getKey()).isEqualTo("HappyFace.jpg"); + assertThat(s3Object.getETag()).isEqualTo("d41d8cd98f00b204e9800998ecf8427e"); + assertThat(s3Object.getSizeAsLong()).isEqualTo(1024L); + assertThat(s3Object.getVersionId()).isEqualTo("096fKKXTRTtl3on89fVO.nfljtsv6qko"); + assertThat(s3Object.getSequencer()).isEqualTo("0055AED6DCD90281E5"); + + assertThat(rec.getGlacierEventData()).isNull(); + assertThat(rec.getIntelligentTieringEventData()).isNull(); + assertThat(rec.getLifecycleEventData()).isNull(); + assertThat(rec.getReplicationEventData()).isNull(); + } + + @Test + void givenEventContainingOptionalFields_whenReadingJson_expectAllFields() { + String eventJson = "{\n" + + " \"Records\":[\n" + + " {\n" + + " \"eventVersion\":\"2.1\",\n" + + " \"eventSource\":\"aws:s3\",\n" + + " \"awsRegion\":\"us-west-2\",\n" + + " \"eventTime\":\"1970-01-01T00:00:00.000Z\",\n" + + " \"eventName\":\"ObjectCreated:Put\",\n" + + " \"userIdentity\":{\n" + + " \"principalId\":\"AIDAJDPLRKLG7UEXAMPLE\"\n" + + " },\n" + + " \"requestParameters\":{\n" + + " \"sourceIPAddress\":\"127.0.0.1\"\n" + + " },\n" + + " \"responseElements\":{\n" + + " \"x-amz-request-id\":\"C3D13FE58DE4C810\",\n" + + " \"x-amz-id-2\":\"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD\"\n" + + " },\n" + + " \"s3\":{\n" + + " \"s3SchemaVersion\":\"1.0\",\n" + + " \"configurationId\":\"testConfigRule\",\n" + + " \"bucket\":{\n" + + " \"name\":\"mybucket\",\n" + + " \"ownerIdentity\":{\n" + + " \"principalId\":\"A3NL1KOZZKExample\"\n" + + " },\n" + + " \"arn\":\"arn:aws:s3:::mybucket\"\n" + + " },\n" + + " \"object\":{\n" + + " \"key\":\"HappyFace.jpg\",\n" + + " \"size\":1024,\n" + + " \"eTag\":\"d41d8cd98f00b204e9800998ecf8427e\",\n" + + " \"versionId\":\"096fKKXTRTtl3on89fVO.nfljtsv6qko\",\n" + + " \"sequencer\":\"0055AED6DCD90281E5\"\n" + + " }\n" + + " },\n" + + " \"glacierEventData\": {\n" + + " \"restoreEventData\": {\n" + + " \"lifecycleRestorationExpiryTime\": \"1970-02-02T00:00:00.000Z\",\n" + + " \"lifecycleRestoreStorageClass\": \"testStorageClass\"\n" + + " }\n" + + " },\n" + + " \"replicationEventData\": {\n" + + " \"replicationRuleId\": \"replicationRuleIdTest\",\n" + + " \"destinationBucket\": \"destinationBucketTest\",\n" + + " \"s3Operation\": \"s3OperationTest\",\n" + + " \"requestTime\": \"requestTimeTest\",\n" + + " \"failureReason\": \"failureReasonTest\",\n" + + " \"threshold\": \"thresholdTest\",\n" + + " \"replicationTime\": \"replicationTimeTest\"\n" + + " },\n" + + " \"intelligentTieringEventData\": {\n" + + " \"destinationAccessTier\": \"destinationAccessTierTest\"\n" + + " },\n" + + " \"lifecycleEventData\": {\n" + + " \"transitionEventData\": {\n" + + " \"destinationStorageClass\": \"destinationStorageClassTest\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + "}\n"; + + S3EventNotification event = S3EventNotification.fromJson(eventJson); + + assertThat(event.getRecords()).hasSize(1); + + // verify constructors + S3EventNotification expected = new S3EventNotification( + Collections.singletonList(new S3EventNotificationRecord( + "us-west-2", + "ObjectCreated:Put", + "aws:s3", + "1970-01-01T00:00:00.000Z", + "2.1", + new RequestParameters("127.0.0.1"), + new ResponseElements( + "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD", "C3D13FE58DE4C810"), + new S3( + "testConfigRule", + new S3Bucket( + "mybucket", + new UserIdentity("A3NL1KOZZKExample"), + "arn:aws:s3:::mybucket"), + new S3Object( + "HappyFace.jpg", + 1024L, + "d41d8cd98f00b204e9800998ecf8427e", + "096fKKXTRTtl3on89fVO.nfljtsv6qko", + "0055AED6DCD90281E5"), + "1.0" + ), + new UserIdentity("AIDAJDPLRKLG7UEXAMPLE"), + new GlacierEventData(new RestoreEventData("1970-02-02T00:00:00.000Z", "testStorageClass")), + new LifecycleEventData(new TransitionEventData("destinationStorageClassTest")), + new IntelligentTieringEventData("destinationAccessTierTest"), + new ReplicationEventData( + "replicationRuleIdTest", + "destinationBucketTest", + "s3OperationTest", + "requestTimeTest", + "failureReasonTest", + "thresholdTest", + "replicationTimeTest") + )) + ); + assertThat(event).isEqualTo(expected); + + S3EventNotificationRecord rec = event.getRecords().get(0); + assertThat(rec).isNotNull(); + + GlacierEventData glacierEventData = rec.getGlacierEventData(); + assertThat(glacierEventData).isNotNull(); + RestoreEventData restoreEvent = glacierEventData.getRestoreEventData(); + assertThat(restoreEvent).isNotNull(); + assertThat(restoreEvent.getLifecycleRestorationExpiryTime()).isEqualTo(Instant.parse("1970-02-02T00:00:00.000Z")); + assertThat(restoreEvent.getLifecycleRestoreStorageClass()).isEqualTo("testStorageClass"); + + LifecycleEventData lifecycle = rec.getLifecycleEventData(); + assertThat(lifecycle).isNotNull(); + TransitionEventData transitionEvent = lifecycle.getTransitionEventData(); + assertThat(transitionEvent).isNotNull(); + assertThat(transitionEvent.getDestinationStorageClass()).isEqualTo("destinationStorageClassTest"); + + IntelligentTieringEventData tieringEventData = rec.getIntelligentTieringEventData(); + assertThat(tieringEventData).isNotNull(); + assertThat(tieringEventData.getDestinationAccessTier()).isEqualTo("destinationAccessTierTest"); + + ReplicationEventData replication = rec.getReplicationEventData(); + assertThat(replication).isNotNull(); + assertThat(replication.getReplicationRuleId()).isEqualTo("replicationRuleIdTest"); + assertThat(replication.getReplicationTime()).isEqualTo("replicationTimeTest"); + assertThat(replication.getDestinationBucket()).isEqualTo("destinationBucketTest"); + assertThat(replication.getRequestTime()).isEqualTo("requestTimeTest"); + assertThat(replication.getFailureReason()).isEqualTo("failureReasonTest"); + assertThat(replication.getThreshold()).isEqualTo("thresholdTest"); + assertThat(replication.getS3Operation()).isEqualTo("s3OperationTest"); + } + + @Test + void emptyJson_shouldContainsNullRecords() { + String json = "{}"; + S3EventNotification event = S3EventNotification.fromJson(json); + assertThat(event).isNotNull(); + assertThat(event.getRecords()).isNull(); + } + + @Test + void nullRecords_shouldContainNullRecords() { + String json = "{\"Records\":null}"; + S3EventNotification event = S3EventNotification.fromJson(json); + assertThat(event).isNotNull(); + assertThat(event.getRecords()).isNull(); + } + + @Test + void emptyRecordList_shouldContainEmptyRecordList() { + String json = "{\"Records\":[]}"; + S3EventNotification event = S3EventNotification.fromJson(json); + assertThat(event).isNotNull(); + assertThat(event.getRecords()).isEmpty(); + } + + @Test + void missingField_shouldBeNull() { + String json = "{\n" + + " \"Records\" : [ {\n" + + " \"eventVersion\" : \"2.1\",\n" + + " \"eventSource\" : \"aws:s3\",\n" + + " \"awsRegion\" : \"us-west-2\",\n" + + " \"eventTime\" : \"1970-01-01T01:01:01.001Z\",\n" + // missing eventName + + " \"userIdentity\" : {\n" + + " \"principalId\" : \"AIDAJDPLRKLG7UEXAMUID\"\n" + + " },\n" + + " \"requestParameters\" : {\n" + + " \"sourceIPAddress\" : \"127.1.2.3\"\n" + + " },\n" + // missing response element + + " \"s3\" : {\n" + + " \"s3SchemaVersion\" : \"1.0\",\n" + + " \"configurationId\" : \"testConfigRule\",\n" + + " \"bucket\" : {\n" + + " \"name\" : \"mybucket-test\",\n" + + " \"ownerIdentity\" : {\n" + + " \"principalId\" : \"A3NL1KOZZKExample\"\n" + + " },\n" + + " \"arn\" : \"arn:aws:s3:::mybucket\"\n" + + " },\n" + + " \"object\" : {\n" + + " \"key\" : \"HappyFace-test.jpg\",\n" + + " \"size\" : 2048,\n" + + " \"eTag\" : \"d41d8cd98f00b204e9800998ecf8etag\",\n" + + " \"versionId\" : \"096fKKXTRTtl3on89fVO.nfljtsv6vid\",\n" + + " \"sequencer\" : \"0055AED6DCD9028SEQ\"\n" + + " }\n" + + " }\n" + + " } ]\n" + + "}"; + + S3EventNotification event = S3EventNotification.fromJson(json); + S3EventNotificationRecord rec = event.getRecords().get(0); + assertThat(rec).isNotNull(); + assertThat(rec.getEventName()).isNull(); + assertThat(rec.getResponseElements()).isNull(); + } + + @Test + void extraFields_areIgnored() { + String json = "{\"Records\":[], \"toto\":123}"; + S3EventNotification event = S3EventNotification.fromJson(json); + assertThat(event).isNotNull(); + assertThat(event.getRecords()).isEmpty(); + } + + @Test + void malformedJson_throwsException() { + String json = "{\"Records\":[], \"toto\"}"; + assertThatThrownBy(() -> S3EventNotification.fromJson(json)).hasCauseInstanceOf(JsonParseException.class); + } +} diff --git a/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationWriterTest.java b/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationWriterTest.java new file mode 100644 index 000000000000..0c8aad9396e5 --- /dev/null +++ b/services-custom/s3-event-notifications/src/test/java/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationWriterTest.java @@ -0,0 +1,347 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.eventnotifications.s3.model; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.eventnotifications.s3.model.GlacierEventData; +import software.amazon.awssdk.eventnotifications.s3.model.IntelligentTieringEventData; +import software.amazon.awssdk.eventnotifications.s3.model.LifecycleEventData; +import software.amazon.awssdk.eventnotifications.s3.model.ReplicationEventData; +import software.amazon.awssdk.eventnotifications.s3.model.RequestParameters; +import software.amazon.awssdk.eventnotifications.s3.model.ResponseElements; +import software.amazon.awssdk.eventnotifications.s3.model.RestoreEventData; +import software.amazon.awssdk.eventnotifications.s3.model.S3; +import software.amazon.awssdk.eventnotifications.s3.model.S3Bucket; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification; +import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotificationRecord; +import software.amazon.awssdk.eventnotifications.s3.model.S3Object; +import software.amazon.awssdk.eventnotifications.s3.model.TransitionEventData; +import software.amazon.awssdk.eventnotifications.s3.model.UserIdentity; + +class S3EventNotificationWriterTest { + + @Test + void testPrettyPrint_requiredFieldOnly() { + S3EventNotification event = new S3EventNotification( + Arrays.asList(new S3EventNotificationRecord( + "us-west-2", + "ObjectCreated:Get", + "aws:s3", + "1970-01-01T01:01:01.001Z", + "2.1", + new RequestParameters("127.1.2.3"), + new ResponseElements( + "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANxid2", "C3D13FE58DE4CRID"), + new S3( + "testConfigRule", + new S3Bucket( + "mybucket-test", + new UserIdentity("A3NL1KOZZKExample"), + "arn:aws:s3:::mybucket"), + new S3Object( + "HappyFace-test.jpg", + 2048L, + "d41d8cd98f00b204e9800998ecf8etag", + "096fKKXTRTtl3on89fVO.nfljtsv6vid", + "0055AED6DCD9028SEQ"), + "1.0" + ), + new UserIdentity("AIDAJDPLRKLG7UEXAMUID") + )) + ); + + String expected = "{\n" + + " \"Records\" : [ {\n" + + " \"eventVersion\" : \"2.1\",\n" + + " \"eventSource\" : \"aws:s3\",\n" + + " \"awsRegion\" : \"us-west-2\",\n" + + " \"eventTime\" : \"1970-01-01T01:01:01.001Z\",\n" + + " \"eventName\" : \"ObjectCreated:Get\",\n" + + " \"userIdentity\" : {\n" + + " \"principalId\" : \"AIDAJDPLRKLG7UEXAMUID\"\n" + + " },\n" + + " \"requestParameters\" : {\n" + + " \"sourceIPAddress\" : \"127.1.2.3\"\n" + + " },\n" + + " \"responseElements\" : {\n" + + " \"x-amz-request-id\" : \"C3D13FE58DE4CRID\",\n" + + " \"x-amz-id-2\" : \"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANxid2\"\n" + + " },\n" + + " \"s3\" : {\n" + + " \"s3SchemaVersion\" : \"1.0\",\n" + + " \"configurationId\" : \"testConfigRule\",\n" + + " \"bucket\" : {\n" + + " \"name\" : \"mybucket-test\",\n" + + " \"ownerIdentity\" : {\n" + + " \"principalId\" : \"A3NL1KOZZKExample\"\n" + + " },\n" + + " \"arn\" : \"arn:aws:s3:::mybucket\"\n" + + " },\n" + + " \"object\" : {\n" + + " \"key\" : \"HappyFace-test.jpg\",\n" + + " \"size\" : 2048,\n" + + " \"eTag\" : \"d41d8cd98f00b204e9800998ecf8etag\",\n" + + " \"versionId\" : \"096fKKXTRTtl3on89fVO.nfljtsv6vid\",\n" + + " \"sequencer\" : \"0055AED6DCD9028SEQ\"\n" + + " }\n" + + " }\n" + + " } ]\n" + + "}"; + assertThat(event.toJsonPretty()).isEqualTo(expected); + } + + @Test + void testToJson_requiredFielsdOnly() { + String expected = "{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-west-2\"," + + "\"eventTime\":\"1970-01-01T01:01:01.001Z\",\"eventName\":\"ObjectCreated:Get\"," + + "\"userIdentity\":{\"principalId\"" + + ":\"AIDAJDPLRKLG7UEXAMUID\"},\"requestParameters\":{\"sourceIPAddress\":\"127.1.2.3\"}," + + "\"responseElements\":{\"x-amz-request-id\":\"C3D13FE58DE4CRID\",\"x-amz-id-2\":" + + "\"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANxid2\"}," + + "\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"testConfigRule\",\"bucket\":" + + "{\"name\":\"mybucket-test\",\"ownerIdentity\":{\"principalId\":\"A3NL1KOZZKExample\"}," + + "\"arn\":\"arn:aws:s3:::mybucket\"},\"object\":{\"key\":\"HappyFace-test.jpg\",\"size\":2048," + + "\"eTag\":\"d41d8cd98f00b204e9800998ecf8etag\",\"versionId\":\"096fKKXTRTtl3on89fVO.nfljtsv6vid\"," + + "\"sequencer\":\"0055AED6DCD9028SEQ\"}}}]}"; + + S3EventNotification event = new S3EventNotification( + Arrays.asList(new S3EventNotificationRecord( + "us-west-2", + "ObjectCreated:Get", + "aws:s3", + "1970-01-01T01:01:01.001Z", + "2.1", + new RequestParameters("127.1.2.3"), + new ResponseElements( + "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANxid2", "C3D13FE58DE4CRID"), + new S3( + "testConfigRule", + new S3Bucket( + "mybucket-test", + new UserIdentity("A3NL1KOZZKExample"), + "arn:aws:s3:::mybucket"), + new S3Object( + "HappyFace-test.jpg", + 2048L, + "d41d8cd98f00b204e9800998ecf8etag", + "096fKKXTRTtl3on89fVO.nfljtsv6vid", + "0055AED6DCD9028SEQ"), + "1.0" + ), + new UserIdentity("AIDAJDPLRKLG7UEXAMUID") + )) + ); + assertThat(event.toJson()).isEqualTo(expected); + } + + @Test + void testPrettyPrint_allFields() { + String expected = "{\n" + + " \"Records\" : [ {\n" + + " \"eventVersion\" : \"2.1\",\n" + + " \"eventSource\" : \"aws:s3\",\n" + + " \"awsRegion\" : \"us-west-2\",\n" + + " \"eventTime\" : \"1970-01-01T01:01:01.001Z\",\n" + + " \"eventName\" : \"ObjectCreated:Put\",\n" + + " \"userIdentity\" : {\n" + + " \"principalId\" : \"AIDAJDPLRKLG7UEXAMPLE\"\n" + + " },\n" + + " \"requestParameters\" : {\n" + + " \"sourceIPAddress\" : \"127.0.0.1\"\n" + + " },\n" + + " \"responseElements\" : {\n" + + " \"x-amz-request-id\" : \"C3D13FE58DE4C810\",\n" + + " \"x-amz-id-2\" : \"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD\"\n" + + " },\n" + + " \"s3\" : {\n" + + " \"s3SchemaVersion\" : \"1.0\",\n" + + " \"configurationId\" : \"testConfigRule\",\n" + + " \"bucket\" : {\n" + + " \"name\" : \"mybucket\",\n" + + " \"ownerIdentity\" : {\n" + + " \"principalId\" : \"A3NL1KOZZKExample\"\n" + + " },\n" + + " \"arn\" : \"arn:aws:s3:::mybucket\"\n" + + " },\n" + + " \"object\" : {\n" + + " \"key\" : \"HappyFace.jpg\",\n" + + " \"size\" : 1024,\n" + + " \"eTag\" : \"d41d8cd98f00b204e9800998ecf8427e\",\n" + + " \"versionId\" : \"096fKKXTRTtl3on89fVO.nfljtsv6qko\",\n" + + " \"sequencer\" : \"0055AED6DCD90281E5\"\n" + + " }\n" + + " },\n" + + " \"glacierEventData\" : {\n" + + " \"restoreEventData\" : {\n" + + " \"lifecycleRestorationExpiryTime\" : \"1971-02-02T01:01:01.001Z\",\n" + + " \"lifecycleRestoreStorageClass\" : \"testStorageClass\"\n" + + " }\n" + + " },\n" + + " \"replicationEventData\" : {\n" + + " \"replicationRuleId\" : \"replicationRuleIdTest\",\n" + + " \"destinationBucket\" : \"destinationBucketTest\",\n" + + " \"s3Operation\" : \"s3OperationTest\",\n" + + " \"requestTime\" : \"requestTimeTest\",\n" + + " \"failureReason\" : \"failureReasonTest\",\n" + + " \"threshold\" : \"thresholdTest\",\n" + + " \"replicationTime\" : \"replicationTimeTest\"\n" + + " },\n" + + " \"intelligentTieringEventData\" : {\n" + + " \"destinationAccessTier\" : \"destinationAccessTierTest\"\n" + + " },\n" + + " \"lifecycleEventData\" : {\n" + + " \"transitionEventData\" : {\n" + + " \"destinationStorageClass\" : \"destinationStorageClassTest\"\n" + + " }\n" + + " }\n" + + " } ]\n" + + "}"; + S3EventNotification event = new S3EventNotification( + Collections.singletonList(new S3EventNotificationRecord( + "us-west-2", + "ObjectCreated:Put", + "aws:s3", + "1970-01-01T01:01:01.001Z", + "2.1", + new RequestParameters("127.0.0.1"), + new ResponseElements( + "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD", "C3D13FE58DE4C810"), + new S3( + "testConfigRule", + new S3Bucket( + "mybucket", + new UserIdentity("A3NL1KOZZKExample"), + "arn:aws:s3:::mybucket"), + new S3Object( + "HappyFace.jpg", + 1024L, + "d41d8cd98f00b204e9800998ecf8427e", + "096fKKXTRTtl3on89fVO.nfljtsv6qko", + "0055AED6DCD90281E5"), + "1.0" + ), + new UserIdentity("AIDAJDPLRKLG7UEXAMPLE"), + new GlacierEventData(new RestoreEventData("1971-02-02T01:01:01.001Z", "testStorageClass")), + new LifecycleEventData(new TransitionEventData("destinationStorageClassTest")), + new IntelligentTieringEventData("destinationAccessTierTest"), + new ReplicationEventData( + "replicationRuleIdTest", + "destinationBucketTest", + "s3OperationTest", + "requestTimeTest", + "failureReasonTest", + "thresholdTest", + "replicationTimeTest"))) + ); + + assertThat(event.toJsonPretty()).isEqualTo(expected); + } + + @Test + void testToJson_allFields() { + String expected = "{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":" + + "\"us-west-2\",\"eventTime\":\"1970-01-01T01:01:01.001Z\",\"eventName\":\"ObjectCreated:Get\"," + + "\"userIdentity\":{\"principalId\":\"PRINCIPALIDTEST\"},\"requestParameters\":{\"sourceIPAddress\":" + + "\"127.1.2.3\"},\"responseElements\":{\"x-amz-request-id\":\"C3D13FE58DE4CRID\",\"x-amz-id-2\":" + + "\"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANxid2\"},\"s3\":{\"s3SchemaVersion\":" + + "\"1.0\",\"configurationId\":\"testConfigRule\",\"bucket\":{\"name\":\"mybucket-test\"," + + "\"ownerIdentity\":{\"principalId\":\"PRINCIPALIDTESTBUCKET\"},\"arn\":\"arn:aws:s3:::mybucket\"}," + + "\"object\":{\"key\":\"HappyFace-test.jpg\",\"size\":2048,\"eTag\":" + + "\"d41d8cd98f00b204e9800998ecf8etag\",\"versionId\":\"096fKKXTRTtl3on89fVO.nfljtsv6vid\"," + + "\"sequencer\":\"0055AED6DCD9028SEQ\"}},\"glacierEventData\":{\"restoreEventData\":" + + "{\"lifecycleRestorationExpiryTime\":\"1971-02-02T01:01:01.001Z\",\"lifecycleRestoreStorageClass\":" + + "\"testStorageClass\"}},\"replicationEventData\":{\"replicationRuleId\":\"replicationRuleIdTest\"," + + "\"destinationBucket\":\"destinationBucketTest\",\"s3Operation\":\"s3OperationTest\"," + + "\"requestTime\":\"requestTimeTest\",\"failureReason\":\"failureReasonTest\",\"threshold\":" + + "\"thresholdTest\",\"replicationTime\":\"replicationTimeTest\"},\"intelligentTieringEventData\":" + + "{\"destinationAccessTier\":\"destinationAccessTierTest\"},\"lifecycleEventData\":" + + "{\"transitionEventData\":{\"destinationStorageClass\":\"destinationStorageClassTest\"}}}]}"; + + S3EventNotification event = new S3EventNotification( + Collections.singletonList(new S3EventNotificationRecord( + "us-west-2", + "ObjectCreated:Get", + "aws:s3", + "1970-01-01T01:01:01.001Z", + "2.1", + new RequestParameters("127.1.2.3"), + new ResponseElements( + "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANxid2", "C3D13FE58DE4CRID"), + new S3( + "testConfigRule", + new S3Bucket( + "mybucket-test", + new UserIdentity("PRINCIPALIDTESTBUCKET"), + "arn:aws:s3:::mybucket"), + new S3Object( + "HappyFace-test.jpg", + 2048L, + "d41d8cd98f00b204e9800998ecf8etag", + "096fKKXTRTtl3on89fVO.nfljtsv6vid", + "0055AED6DCD9028SEQ"), + "1.0" + ), + new UserIdentity("PRINCIPALIDTEST"), + new GlacierEventData(new RestoreEventData("1971-02-02T01:01:01.001Z", "testStorageClass")), + new LifecycleEventData(new TransitionEventData("destinationStorageClassTest")), + new IntelligentTieringEventData("destinationAccessTierTest"), + new ReplicationEventData( + "replicationRuleIdTest", + "destinationBucketTest", + "s3OperationTest", + "requestTimeTest", + "failureReasonTest", + "thresholdTest", + "replicationTimeTest"))) + ); + + assertThat(event.toJson()).isEqualTo(expected); + } + + @Test + void nullList() { + S3EventNotification event = new S3EventNotification(null); + assertThat(event.toJson()).isEqualTo("{\"Records\":null}"); + } + + @Test + void emptyList() { + S3EventNotification event = new S3EventNotification(Collections.emptyList()); + assertThat(event.toJson()).isEqualTo("{\"Records\":[]}"); + } + + @Test + void nullRecordValue() { + S3EventNotification event = new S3EventNotification(Collections.singletonList( + new S3EventNotificationRecord(null, null, null, null, null, null, null, null, null) + )); + assertThat(event.toJson()).isEqualTo( + "{\"Records\":[{" + + "\"eventVersion\":null," + + "\"eventSource\":null," + + "\"awsRegion\":null," + + "\"eventTime\":null," + + "\"eventName\":null," + + "\"userIdentity\":null," + + "\"requestParameters\":null," + + "\"responseElements\":null," + + "\"s3\":null}]}"); + } +} diff --git a/services-custom/s3-event-notifications/src/test/resources/log4j2.properties b/services-custom/s3-event-notifications/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..827f0c09a093 --- /dev/null +++ b/services-custom/s3-event-notifications/src/test/resources/log4j2.properties @@ -0,0 +1,41 @@ +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file 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. +# + +status = warn + +appender.console.type = Console +appender.console.name = ConsoleAppender +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n%throwable + +rootLogger.level = info +rootLogger.appenderRef.stdout.ref = ConsoleAppender + +# Uncomment below to enable more specific logging +# +#logger.sdk.name = software.amazon.awssdk +#logger.sdk.level = debug +# +#logger.tm.name = software.amazon.awssdk.transfer.s3 +#logger.tm.level = info +# +#logger.request.name = software.amazon.awssdk.request +#logger.request.level = debug +# +#logger.apache.name = org.apache.http.wire +#logger.apache.level = debug +# +#logger.netty.name = io.netty.handler.logging +#logger.netty.level = debug diff --git a/test/tests-coverage-reporting/pom.xml b/test/tests-coverage-reporting/pom.xml index 7a301b53d4f2..f4c8b2106a90 100644 --- a/test/tests-coverage-reporting/pom.xml +++ b/test/tests-coverage-reporting/pom.xml @@ -276,6 +276,11 @@ software.amazon.awssdk ${awsjavasdk.version} + + software.amazon.awssdk + s3-event-notifications + ${awsjavasdk.version} + sso software.amazon.awssdk diff --git a/third-party/third-party-jackson-core/pom.xml b/third-party/third-party-jackson-core/pom.xml index 40e7baa70302..0cef904012bb 100644 --- a/third-party/third-party-jackson-core/pom.xml +++ b/third-party/third-party-jackson-core/pom.xml @@ -8,7 +8,7 @@ ~ ~ http://aws.amazon.com/apache2.0 ~ - ~ or in the "license" f4ile accompanying this file. This file is distributed + ~ or in the "license" file accompanying this file. This file 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. diff --git a/third-party/third-party-slf4j-api/pom.xml b/third-party/third-party-slf4j-api/pom.xml index f63a8c63262d..7928fca18c40 100644 --- a/third-party/third-party-slf4j-api/pom.xml +++ b/third-party/third-party-slf4j-api/pom.xml @@ -8,7 +8,7 @@ ~ ~ http://aws.amazon.com/apache2.0 ~ - ~ or in the "license" f4ile accompanying this file. This file is distributed + ~ or in the "license" file accompanying this file. This file 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.