From a130fda0f1fae6119c7486b4b10053262685faf3 Mon Sep 17 00:00:00 2001 From: zhuxiaolong37 Date: Tue, 13 May 2025 10:54:37 +0800 Subject: [PATCH] add seal append object --- src/main/java/com/aliyun/oss/OSS.java | 18 +++++ src/main/java/com/aliyun/oss/OSSClient.java | 5 ++ .../aliyun/oss/common/utils/HttpHeaders.java | 2 +- .../oss/internal/OSSObjectOperation.java | 31 ++++++++ .../oss/internal/RequestParameters.java | 1 + .../com/aliyun/oss/model/ObjectMetadata.java | 17 +++++ .../SealAppendObjectTest.java | 70 +++++++++++++++++++ 7 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/aliyun/oss/integrationtests/SealAppendObjectTest.java diff --git a/src/main/java/com/aliyun/oss/OSS.java b/src/main/java/com/aliyun/oss/OSS.java index a23dff47..333d5528 100644 --- a/src/main/java/com/aliyun/oss/OSS.java +++ b/src/main/java/com/aliyun/oss/OSS.java @@ -5685,4 +5685,22 @@ public UdfApplicationLog getUdfApplicationLog(GetUdfApplicationLogRequest getUdf */ public ListAccessPointsResult listBucketAccessPoints(ListBucketAccessPointsRequest listBucketAccessPointsRequest) throws OSSException, ClientException; + /** + * Used to stop an Object of the type Appendable Object from further writing. + * + * @param bucketName + * Bucket name. + * @param key + * Object key. + * + * @return A {@link VoidResult} instance wrapped void return and + * contains some basic response options, such as requestId. + * + * @throws OSSException + * If any errors occurred in OSS while processing the request. + * @throws ClientException + * If any errors are encountered in the client while making the + * request or handling the response. + */ + public VoidResult sealAppendObject(String bucketName, String key) throws OSSException, ClientException; } diff --git a/src/main/java/com/aliyun/oss/OSSClient.java b/src/main/java/com/aliyun/oss/OSSClient.java index c1335d0c..d5b8c3f1 100644 --- a/src/main/java/com/aliyun/oss/OSSClient.java +++ b/src/main/java/com/aliyun/oss/OSSClient.java @@ -2162,6 +2162,11 @@ public ListAccessPointsResult listBucketAccessPoints(ListBucketAccessPointsReque return bucketOperation.listBucketAccessPoints(listBucketAccessPointsRequest); } + @Override + public VoidResult sealAppendObject(String bucketName, String key) throws OSSException, ClientException { + return this.objectOperation.sealAppendObject(new GenericRequest(bucketName, key)); + } + @Override public void shutdown() { try { diff --git a/src/main/java/com/aliyun/oss/common/utils/HttpHeaders.java b/src/main/java/com/aliyun/oss/common/utils/HttpHeaders.java index 7cfdfd70..c029c5af 100644 --- a/src/main/java/com/aliyun/oss/common/utils/HttpHeaders.java +++ b/src/main/java/com/aliyun/oss/common/utils/HttpHeaders.java @@ -40,5 +40,5 @@ public interface HttpHeaders { public static final String RANGE = "Range"; public static final String LOCATION = "Location"; public static final String CONNECTION = "Connection"; - + public static final String SEALED_TIME = "x-oss-sealed-time"; } diff --git a/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java b/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java index 4cc0e266..ac383b7e 100644 --- a/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java +++ b/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java @@ -1450,6 +1450,37 @@ public String calculatePostSignature(String postPolicy, Date date) throws Client } } + /** + * seal append object. + */ + public VoidResult sealAppendObject(GenericRequest genericRequest) throws OSSException, ClientException { + + assertParameterNotNull(genericRequest, "genericRequest"); + + String bucketName = genericRequest.getBucketName(); + String key = genericRequest.getKey(); + + assertParameterNotNull(bucketName, "bucketName"); + ensureBucketNameValid(bucketName); + assertParameterNotNull(key, "key"); + ensureObjectKeyValid(key); + + Map headers = new HashMap(); + populateRequestPayerHeader(headers, genericRequest.getRequestPayer()); + + Map params = new HashMap(); + params.put(SEAL, null); + + RequestMessage request = new OSSRequestMessageBuilder(getInnerClient()).setEndpoint(getEndpoint(genericRequest)) + .setMethod(HttpMethod.POST).setBucket(bucketName).setKey(key).setHeaders(headers).setParameters(params) + .setInputStream(new ByteArrayInputStream(new byte[0])).setInputSize(0) + .setOriginalRequest(genericRequest) + .build(); + + return doOperation(request, requestIdResponseParser, bucketName, key, true); + } + + private static void addHeaderIfNotNull(Map headers, String header, String value) { if (value != null) { headers.put(header, value); diff --git a/src/main/java/com/aliyun/oss/internal/RequestParameters.java b/src/main/java/com/aliyun/oss/internal/RequestParameters.java index 2fbc4c4f..e52a04b1 100644 --- a/src/main/java/com/aliyun/oss/internal/RequestParameters.java +++ b/src/main/java/com/aliyun/oss/internal/RequestParameters.java @@ -124,6 +124,7 @@ public final class RequestParameters { public static final String COMP_QUERY = "query"; public static final String META_QUERY = "metaQuery"; public static final String MODE = "mode"; + public static final String SEAL = "seal"; public static final String STAT = "stat"; public static final String HISTORY = "history"; diff --git a/src/main/java/com/aliyun/oss/model/ObjectMetadata.java b/src/main/java/com/aliyun/oss/model/ObjectMetadata.java index 019181de..9109a2dc 100644 --- a/src/main/java/com/aliyun/oss/model/ObjectMetadata.java +++ b/src/main/java/com/aliyun/oss/model/ObjectMetadata.java @@ -444,6 +444,23 @@ public boolean isRestoreCompleted() { } return true; } + + /** + * Gets the {@link Date} value of the "x-oss-sealed-time" header in Rfc822 format. If + * sealed time is not set, then the value is null. + * + * @return sealed time header's value in Rfc822. + * @throws ParseException + * The value is not in the Rfc822 format. + */ + public Date getSealedTime() throws ParseException { + String sealedTime = (String) metadata.get(OSSHeaders.SEALED_TIME); + + if (sealedTime != null) + return DateUtil.parseRfc822Date((String) metadata.get(OSSHeaders.SEALED_TIME)); + + return null; + } public void setObjectTagging(Map tags) { if (tags != null && !tags.isEmpty()) { diff --git a/src/test/java/com/aliyun/oss/integrationtests/SealAppendObjectTest.java b/src/test/java/com/aliyun/oss/integrationtests/SealAppendObjectTest.java new file mode 100644 index 00000000..27290fc4 --- /dev/null +++ b/src/test/java/com/aliyun/oss/integrationtests/SealAppendObjectTest.java @@ -0,0 +1,70 @@ +package com.aliyun.oss.integrationtests; + +import com.aliyun.oss.OSSException; +import com.aliyun.oss.common.utils.DateUtil; +import com.aliyun.oss.internal.OSSHeaders; +import com.aliyun.oss.model.*; +import junit.framework.Assert; +import org.junit.Test; +import java.io.InputStream; +import static com.aliyun.oss.integrationtests.TestUtils.genFixedLengthInputStream; + +public class SealAppendObjectTest extends TestBase { + + @Test + public void testSealAppendObject() { + String key = "seal-append-object.txt"; + final long instreamLength = 128 * 1024; + + try { + InputStream instream = genFixedLengthInputStream(instreamLength); + AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, key, instream, null); + appendObjectRequest.setPosition(0L); + AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest); + + // get object + OSSObject o = ossClient.getObject(bucketName, key); + Assert.assertEquals(key, o.getKey()); + Assert.assertEquals(instreamLength, o.getObjectMetadata().getContentLength()); + Assert.assertEquals(APPENDABLE_OBJECT_TYPE, o.getObjectMetadata().getObjectType()); + + Assert.assertEquals(appendObjectResult.getRequestId().length(), REQUEST_ID_LEN); + Assert.assertEquals(o.getRequestId().length(), REQUEST_ID_LEN); + Assert.assertNull(o.getResponse().getHeaders().get("x-oss-sealed-time")); + Assert.assertNull(o.getObjectMetadata().getSealedTime()); + + // head object + ObjectMetadata metadata = ossClient.headObject(bucketName, key); + Assert.assertNull(metadata.getSealedTime()); + Assert.assertNull(metadata.getRawMetadata().get(OSSHeaders.SEALED_TIME)); + + // seal append object + try { + ossClient.sealAppendObject(bucketName, key); + + // get object + OSSObject obj = ossClient.getObject(bucketName, key); + Assert.assertEquals(key, obj.getKey()); + Assert.assertEquals(instreamLength, obj.getObjectMetadata().getContentLength()); + Assert.assertEquals(APPENDABLE_OBJECT_TYPE, obj.getObjectMetadata().getObjectType()); + + Assert.assertEquals(appendObjectResult.getRequestId().length(), REQUEST_ID_LEN); + Assert.assertEquals(obj.getRequestId().length(), REQUEST_ID_LEN); + Assert.assertNotNull(obj.getResponse().getHeaders().get("x-oss-sealed-time")); + Assert.assertNotNull(obj.getObjectMetadata().getSealedTime()); + Assert.assertEquals(obj.getObjectMetadata().getSealedTime(), DateUtil.parseRfc822Date(obj.getResponse().getHeaders().get("x-oss-sealed-time"))); + + // head object + ObjectMetadata metadata2 = ossClient.headObject(bucketName, key); + Assert.assertNotNull(metadata2.getSealedTime()); + Assert.assertNotNull(metadata2.getRawMetadata().get(OSSHeaders.SEALED_TIME)); + Assert.assertEquals(metadata2.getSealedTime(), DateUtil.parseRfc822Date(metadata2.getRawMetadata().get(OSSHeaders.SEALED_TIME).toString())); + + } catch (OSSException ex) { + Assert.assertEquals("MethodNotAllowed", ex.getErrorCode()); + } + } catch (Exception ex) { + Assert.fail(ex.getMessage()); + } + } +}