Skip to content

Commit

Permalink
Add support for GetObjectAttributes API - WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
afranken committed Nov 21, 2022
1 parent de150dc commit fa6f558
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
import static com.adobe.testing.s3mock.util.AwsHttpHeaders.X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID;
import static com.adobe.testing.s3mock.util.AwsHttpHeaders.X_AMZ_TAGGING;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.ACL;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.ATTRIBUTES;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.DELETE;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.LEGAL_HOLD;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_ACL;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_ATTRIBUTES;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_LEGAL_HOLD;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_LIFECYCLE;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_RETENTION;
Expand Down Expand Up @@ -61,11 +63,13 @@
import com.adobe.testing.s3mock.dto.CopySource;
import com.adobe.testing.s3mock.dto.Delete;
import com.adobe.testing.s3mock.dto.DeleteResult;
import com.adobe.testing.s3mock.dto.GetObjectAttributesOutput;
import com.adobe.testing.s3mock.dto.LegalHold;
import com.adobe.testing.s3mock.dto.ObjectKey;
import com.adobe.testing.s3mock.dto.Owner;
import com.adobe.testing.s3mock.dto.Range;
import com.adobe.testing.s3mock.dto.Retention;
import com.adobe.testing.s3mock.dto.StorageClass;
import com.adobe.testing.s3mock.dto.Tag;
import com.adobe.testing.s3mock.dto.Tagging;
import com.adobe.testing.s3mock.service.BucketService;
Expand Down Expand Up @@ -222,7 +226,8 @@ public ResponseEntity<Void> deleteObject(@PathVariable String bucketName,
NOT_TAGGING,
NOT_LEGAL_HOLD,
NOT_RETENTION,
NOT_ACL
NOT_ACL,
NOT_ATTRIBUTES
},
method = RequestMethod.GET,
produces = {
Expand Down Expand Up @@ -493,6 +498,48 @@ public ResponseEntity<Void> putObjectRetention(@PathVariable String bucketName,
.build();
}

/**
* Returns the attributes for an object.
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html">API Reference</a>
*
* @param bucketName The Bucket's name
*/
@RequestMapping(
value = "/{bucketName:[a-z0-9.-]+}/{*key}",
params = {
ATTRIBUTES
},
method = RequestMethod.GET,
produces = APPLICATION_XML_VALUE
)
public ResponseEntity<GetObjectAttributesOutput> getObjectAttributes(
@PathVariable String bucketName,
@PathVariable ObjectKey key,
@RequestHeader(value = IF_MATCH, required = false) List<String> match,
@RequestHeader(value = IF_NONE_MATCH, required = false) List<String> noneMatch) {
//TODO: needs modified-since handling, see API
bucketService.verifyBucketExists(bucketName);

//this is for either an object request, or a parts request.

S3ObjectMetadata s3ObjectMetadata = objectService.verifyObjectExists(bucketName, key.getKey());
objectService.verifyObjectMatching(match, noneMatch, s3ObjectMetadata);

GetObjectAttributesOutput response = new GetObjectAttributesOutput(
null, //checksum currently not persisted
s3ObjectMetadata.getEtag(),
null, //parts not supported right now
Long.parseLong(s3ObjectMetadata.getSize()),
StorageClass.STANDARD //storage class currently not persisted
);

return ResponseEntity
.ok()
.lastModified(s3ObjectMetadata.getLastModified())
.body(response);
}


/**
* Adds an object to a bucket.
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html">API Reference</a>
Expand Down
47 changes: 47 additions & 0 deletions server/src/main/java/com/adobe/testing/s3mock/dto/Checksum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2017-2022 Adobe.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.adobe.testing.s3mock.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;

/**
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_Checksum.html">API Reference</a>.
*/
@JsonRootName("Checksum")
public class Checksum {

@JsonProperty("ChecksumCRC32")
private String checksumCRC32;

@JsonProperty("ChecksumCRC32C")
private String checksumCRC32C;

@JsonProperty("ChecksumSHA1")
private String checksumSHA1;

@JsonProperty("ChecksumSHA256")
private String checksumSHA256;

public Checksum(String checksumCRC32, String checksumCRC32C, String checksumSHA1,
String checksumSHA256) {
this.checksumCRC32 = checksumCRC32;
this.checksumCRC32C = checksumCRC32C;
this.checksumSHA1 = checksumSHA1;
this.checksumSHA256 = checksumSHA256;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2017-2022 Adobe.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.adobe.testing.s3mock.dto;

import static com.adobe.testing.s3mock.util.EtagUtil.normalizeEtag;

import com.adobe.testing.s3mock.store.S3ObjectMetadata;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import java.util.List;

@JsonRootName("GetObjectAttributesOutput")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class GetObjectAttributesOutput {

@JsonProperty("Checksum")
private Checksum checksum;

@JsonProperty("ETag")
private String etag;

@JsonProperty("ObjectParts")
@JacksonXmlElementWrapper(useWrapping = false)
private List<GetObjectAttributesParts> objectParts;

@JsonProperty("ObjectSize")
private Long objectSize;

@JsonProperty("StorageClass")
private StorageClass storageClass;

public GetObjectAttributesOutput(Checksum checksum, String etag,
List<GetObjectAttributesParts> objectParts, Long objectSize, StorageClass storageClass) {
this.checksum = checksum;
this.etag = normalizeEtag(etag);
this.objectParts = objectParts;
this.objectSize = objectSize;
this.storageClass = storageClass;
}

GetObjectAttributesOutput from(S3ObjectMetadata metadata) {
return new GetObjectAttributesOutput(null,
metadata.getEtag(),
null,
Long.valueOf(metadata.getSize()),
null);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2017-2022 Adobe.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.adobe.testing.s3mock.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import java.util.List;

/**
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributesParts.html">API Reference</a>.
*/
@JsonRootName("GetObjectAttributesParts")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class GetObjectAttributesParts {

@JsonProperty("MaxParts")
private int maxParts;

@JsonProperty("IsTruncated")
private boolean isTruncated;

@JsonProperty("NextPartNumberMarker")
private int nextPartNumberMarker;

@JsonProperty("PartNumberMarker")
private int partNumberMarker;

@JsonProperty("TotalPartsCount")
private int totalPartsCount;

@JsonProperty("Parts")
@JacksonXmlElementWrapper(useWrapping = false)
private List<ObjectPart> parts;

public GetObjectAttributesParts(int maxParts, boolean isTruncated, int nextPartNumberMarker,
int partNumberMarker, int totalPartsCount, List<ObjectPart> parts) {
this.maxParts = maxParts;
this.isTruncated = isTruncated;
this.nextPartNumberMarker = nextPartNumberMarker;
this.partNumberMarker = partNumberMarker;
this.totalPartsCount = totalPartsCount;
this.parts = parts;
}
}
56 changes: 56 additions & 0 deletions server/src/main/java/com/adobe/testing/s3mock/dto/ObjectPart.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2017-2022 Adobe.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.adobe.testing.s3mock.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;

/**
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_ObjectPart.html">API Reference</a>.
*/
@JsonRootName("ObjectPart")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class ObjectPart {
@JsonProperty("ChecksumCRC32")
private String checksumCRC32;

@JsonProperty("ChecksumCRC32C")
private String checksumCRC32C;

@JsonProperty("ChecksumSHA1")
private String checksumSHA1;

@JsonProperty("ChecksumSHA256")
private String checksumSHA256;

@JsonProperty("Size")
private Long size;

@JsonProperty("PartNumber")
protected Integer partNumber;

public ObjectPart(String checksumCRC32, String checksumCRC32C, String checksumSHA1,
String checksumSHA256, Long size, Integer partNumber) {
this.checksumCRC32 = checksumCRC32;
this.checksumCRC32C = checksumCRC32C;
this.checksumSHA1 = checksumSHA1;
this.checksumSHA256 = checksumSHA256;
this.size = size;
this.partNumber = partNumber;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public class AwsHttpParameters {
public static final String NOT_RETENTION = NOT + RETENTION;
public static final String LIFECYCLE = "lifecycle";
public static final String NOT_LIFECYCLE = NOT + LIFECYCLE;
public static final String ATTRIBUTES = "attributes";
public static final String NOT_ATTRIBUTES = NOT + ATTRIBUTES;

private AwsHttpParameters() {
// empty private constructor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.adobe.testing.s3mock.dto;

import static com.adobe.testing.s3mock.dto.DtoTestUtil.serializeAndAssert;

import java.io.IOException;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

class GetObjectAttributesOutputTest {

@Test
void testSerialization_object(TestInfo testInfo) throws IOException {
GetObjectAttributesOutput iut = new GetObjectAttributesOutput(
null,
"etag",
null,
1L,
StorageClass.STANDARD
);

serializeAndAssert(iut, testInfo);
}

@Test
void testSerialization_multiPart(TestInfo testInfo) throws IOException {
ObjectPart part = new ObjectPart(null,
null,
null,
null,
1L,
1);
GetObjectAttributesParts getObjectAttributesParts = new GetObjectAttributesParts(
1000,
false,
0,
0,
0,
Collections.singletonList(part)
);
GetObjectAttributesOutput iut = new GetObjectAttributesOutput(
null,
"etag",
Collections.singletonList(getObjectAttributesParts),
1L,
StorageClass.STANDARD
);

serializeAndAssert(iut, testInfo);
}

}
Loading

0 comments on commit fa6f558

Please sign in to comment.