使用 Java

IBM Cloud® Object Storage SDK for Java 提供可充分利用 IBM Cloud Object Storage 的特性。

IBM Cloud Object Storage SDK for Java 包羅萬象,有許多特性和功能超出本手冊的描述範圍。 如需詳細的類別及方法文件,請參閱 Javadoc。 原始碼可以在 GitHub 儲存庫中找到。

取得 SDK

使用 IBM Cloud Object Storage Java SDK 最簡單的方法是使用 Maven 來管理相依關係。 如果您不熟悉 Maven,可以使用 Maven in 5-Minutes 指南開始使用。

Maven 會使用稱為 pom.xml 的檔案,來指定 Java 專案所需的程式庫(及其版本)。 以下是使用 IBM Cloud Object Storage Java SDK 連接至 Object Storage 的範例 pom.xml 檔。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.cos</groupId>
    <artifactId>docs</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>com.ibm.cos</groupId>
            <artifactId>ibm-cos-java-sdk</artifactId>
            <version>2.8.0</version>
        </dependency>
    </dependencies>
</project>

建立用戶端及讀取認證

在下列範例中,是透過提供認證資訊(API 金鑰及服務實例 ID),來建立及配置用戶端 cos。 這些值也可以自動從 credentials 檔案或環境變數中取得。

產生服務認證後,會將產生的 JSON 文件儲存為 ~/.bluemix/cos_credentials。 除非在建立用戶端期間,明確地設定其他認證,否則 SDK 將自動從此檔案讀取認證。 如果 cos_credentials 檔案包含 HMAC 金鑰,用戶端將以簽章進行鑑別,否則用戶端會使用提供的 API 金鑰以持有人記號進行鑑別。

如果從 AWS S3 移轉,您也可以使用下列格式從 ~/.aws/credentials 讀取認證資料:

[default]
aws_access_key_id = {API_KEY}
aws_secret_access_key = {SERVICE_INSTANCE_ID}

如果 ~/.bluemix/cos_credentials~/.aws/credentials 同時存在,則 cos_credentials 會優先。

如需用戶端建構的詳細資料,請參閱 Javadoc

程式碼範例

在程式碼中,您必須移除這裡提供的角括弧或任何其他多餘字元,以作為圖解。

讓我們從一個完整的範例類別開始,執行一些基本功能,然後再個別探索類別。 此 CosExample 類別會列出現有儲存區中的物件、建立新的儲存區,然後列出服務實例中的所有儲存區。

收集必要資訊

  • bucketNamenewBucketName唯一且 DNS 安全的字串。 因為儲存區名稱在整個系統中是唯一的,因此如果此範例執行多次,將需要變更這些值。 請注意,名稱在刪除後會保留 10 到 15 分鐘。
  • apiKey 是在 服務憑證 中找到的值,如 apikey
  • serviceInstanceId 是在 服務憑證 中找到的值,如 resource_instance_id
  • endpointUrl 是服務端點 URL,包含 https:// 通訊協定。 這不是服務憑證 中找到的 endpoints 值。 如需端點的相關資訊,請參閱端點及儲存空間位置
  • storageClass 是與 endpoint 值對應的 有效佈建代碼。 然後,這會用來作為 S3 API LocationConstraint 變數。
  • location 應該設定為 storageClass 的位置部分。 若為 us-south-standard,這將是 us-south。 此變數僅用於計算 HMAC 簽章,但任何用戶端(包括使用 IAM API 金鑰的這個範例)都需要此變數。
    package com.cos;

    import java.time.LocalDateTime;
    import java.util.List;

    import com.ibm.cloud.objectstorage.ClientConfiguration;
    import com.ibm.cloud.objectstorage.auth.AWSCredentials;
    import com.ibm.cloud.objectstorage.auth.AWSStaticCredentialsProvider;
    import com.ibm.cloud.objectstorage.client.builder.AwsClientBuilder.EndpointConfiguration;
    import com.ibm.cloud.objectstorage.services.s3.AmazonS3;
    import com.ibm.cloud.objectstorage.services.s3.AmazonS3ClientBuilder;
    import com.ibm.cloud.objectstorage.services.s3.model.Bucket;
    import com.ibm.cloud.objectstorage.services.s3.model.ListObjectsRequest;
    import com.ibm.cloud.objectstorage.services.s3.model.ObjectListing;
    import com.ibm.cloud.objectstorage.services.s3.model.S3ObjectSummary;
    import com.ibm.cloud.objectstorage.oauth.BasicIBMOAuthCredentials;

    public class CosExample
    {
        public static void main(String[] args)
        {
            String bucketName = "<BUCKET_NAME>";  // eg my-unique-bucket-name
            String newBucketName = "<NEW_BUCKET_NAME>"; // eg my-other-unique-bucket-name
            String apiKey = "<API_KEY>"; // eg "W00YiRnLW4k3fTjMB-oiB-2ySfTrFBIQQWanc--P3byk"
            String serviceInstanceId = "<SERVICE_INSTANCE_ID"; // eg "crn:v1:bluemix:public:cloud-object-storage:global:a/3bf0d9003abfb5d29761c3e97696b71c:d6f04d83-6c4f-4a62-a165-696756d63903::"
            String endpointUrl = "https://s3.us-south.cloud-object-storage.appdomain.cloud"; // this could be any service endpoint

            String storageClass = "us-south-standard";
            String location = "us"; // not an endpoint, but used in a custom function below to obtain the correct URL

            System.out.println("Current time: " + LocalDateTime.now());
            AmazonS3 cosClient = createClient(apiKey, serviceInstanceId, endpointUrl, location);
            listObjects(cosClient, bucketName);
            createBucket(cosClient, newBucketName, storageClass);
            listBuckets(cosClient);
        }

        public static AmazonS3 createClient(String apiKey, String serviceInstanceId, String endpointUrl, String location)
        {
            AWSCredentials credentials = new BasicIBMOAuthCredentials(apiKey, serviceInstanceId);
            ClientConfiguration clientConfig = new ClientConfiguration()
                    .withRequestTimeout(5000)
                    .withTcpKeepAlive(true);

            return AmazonS3ClientBuilder
                    .standard()
                    .withCredentials(new AWSStaticCredentialsProvider(credentials))
                    .withEndpointConfiguration(new EndpointConfiguration(endpointUrl, location))
                    .withPathStyleAccessEnabled(true)
                    .withClientConfiguration(clientConfig)
                    .build();
        }

        public static void listObjects(AmazonS3 cosClient, String bucketName)
        {
            System.out.println("Listing objects in bucket " + bucketName);
            ObjectListing objectListing = cosClient.listObjects(new ListObjectsRequest().withBucketName(bucketName));
            for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                System.out.println(" - " + objectSummary.getKey() + "  " + "(size = " + objectSummary.getSize() + ")");
            }
            System.out.println();
        }

        public static void createBucket(AmazonS3 cosClient, String bucketName, String storageClass)
        {
            cosClient.createBucket(bucketName, storageClass);
        }

        public static void listBuckets(AmazonS3 cosClient)
        {
            System.out.println("Listing buckets");
            final List<Bucket> bucketList = cosClient.listBuckets();
            for (final Bucket bucket : bucketList) {
                System.out.println(bucket.getName());
            }
            System.out.println();
        }
    }

起始設定配置

private static String COS_ENDPOINT = "<endpoint>"; // eg "https://s3.us.cloud-object-storage.appdomain.cloud"
private static String COS_API_KEY_ID = "<api-key>"; // eg "0viPHOY7LbLNa9eLftrtHPpTjoGv6hbLD1QalRXikliJ"
private static String COS_AUTH_ENDPOINT = "https://iam.cloud.ibm.com/identity/token";
private static String COS_SERVICE_CRN = "<resource-instance-id>"; // "crn:v1:bluemix:public:cloud-object-storage:global:a/<CREDENTIAL_ID_AS_GENERATED>:<SERVICE_ID_AS_GENERATED>::"
private static String COS_BUCKET_LOCATION = "<location>"; // eg "us"

public static void main(String[] args)
{
    SDKGlobalConfiguration.IAM_ENDPOINT = COS_AUTH_ENDPOINT;

    try {
        _cos = createClient(COS_API_KEY_ID, COS_SERVICE_CRN, COS_ENDPOINT, COS_BUCKET_LOCATION);
    } catch (SdkClientException sdke) {
        System.out.printf("SDK Error: %s\n", sdke.getMessage());
    } catch (Exception e) {
        System.out.printf("Error: %s\n", e.getMessage());
    }
}

public static AmazonS3 createClient(String api_key, String service_instance_id, String endpoint_url, String location)
{
    AWSCredentials credentials = new BasicIBMOAuthCredentials(api_key, service_instance_id);
    ClientConfiguration clientConfig = new ClientConfiguration().withRequestTimeout(5000);
    clientConfig.setUseTcpKeepAlive(true);

    AmazonS3 cos = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials))
            .withEndpointConfiguration(new EndpointConfiguration(endpoint_url, location)).withPathStyleAccessEnabled(true)
            .withClientConfiguration(clientConfig).build();

    return cos;
}

金鑰值

  • <endpoint>- 雲端 Object Storage 的公用端點 (可從 IBM Cloud Dashboard 取得)。 如需端點的相關資訊,請參閱端點及儲存空間位置
  • <api-key>- 建立服務憑證時產生的 api 金鑰 (建立和刪除範例需要寫入存取權限)
  • <resource-instance-id>- 雲端 Object Storage 的資源 ID (可透過 IBM Cloud CLIIBM Cloud Dashboard 取得)
  • <location>- 您的雲端 Object Storage 的預設位置 (必須與 <endpoint> 使用的區域相符 )

SDK 參照

類別

決定端點

下面的方法可用來根據儲存區位置、端點類型(公用或專用)及特定地區(選用)來決定服務端點。 如需端點的相關資訊,請參閱端點及儲存空間位置

/**
* Returns a service endpoint based on the
* storage class location (i.e. us-standard, us-south-standard),
* endpoint type (public or private)
*/
public static String getEndpoint(String location, String endPointType) {
    return getEndpoint(location, "", endPointType);
}

/**
* Returns a service endpoint based on the
* storage class location (i.e. us-standard, us-south-standard),
* specific region if desired (i.e. sanjose, amsterdam) - only use if you want a specific regional endpoint,
* endpoint type (public or private)
*/
public static String getEndpoint(String location, String region, String endpointType) {
    HashMap locationMap = new HashMap<String, String>();
    locationMap.put("us", "s3-api.us-geo");
    locationMap.put("us-dallas", "s3-api.dal-us-geo");
    locationMap.put("us-sanjose", "s3-api.sjc-us-geo");
    locationMap.put("us-washington", "s3-api.wdc-us-geo");
    locationMap.put("us-south", "s3.us-south");
    locationMap.put("us-east", "s3.us-east");
    locationMap.put("eu", "s3.eu-geo");
    locationMap.put("eu-amsterdam", "s3.ams-eu-geo");
    locationMap.put("eu-frankfurt", "s3.fra-eu-geo");
/**    locationMap.put("eu-milan", "s3.mil-eu-geo");*/
    locationMap.put("eu-gb", "s3.eu-gb");
    locationMap.put("eu-germany", "s3.eu-de");
    locationMap.put("ap", "s3.ap-geo");
    locationMap.put("ap-tokyo", "s3.tok-ap-geo");
    locationMap.put("che01", "s3.che01");
    locationMap.put("mel01", "s3.mel01");
    locationMap.put("tor01", "s3.tor01");

    String key = location.substring(0, location.lastIndexOf("-")) + (region != null && !region.isEmpty() ? "-" + region : "");
    String endpoint = locationMap.getOrDefault(key, null).toString();

    if (endpoint != null) {
        if (endpointType.toLowerCase() == "private")
            endpoint += ".objectstorage.service.networklayer.com";
        else
            endpoint += ".objectstorage.s3.us-south.cloud-object-storage.appdomain.cloud.net";
    }

    return endpoint;
}

建立新的儲存區

public static void createBucket(String bucketName) {
    System.out.printf("Creating new bucket: %s\n", bucketName);
    _cos.createBucket(bucketName);
    System.out.printf("Bucket: %s created!\n", bucketName);
}

建立具有不同儲存空間類別的儲存區

LocationConstraint 的有效佈建碼清單可以在儲存空間類別手冊中參閱。

cos.createBucket("sample", "us-vault"); // the name of the bucket, and the storage class (LocationConstraint)

SDK 參照

建立新的文字檔

public static void createTextFile(String bucketName, String itemName, String fileText) {
    System.out.printf("Creating new item: %s\n", itemName);

    byte[] arr = fileText.getBytes(StandardCharsets.UTF_8);
    InputStream newStream = new ByteArrayInputStream(arr);

    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(arr.length);

    PutObjectRequest req = new PutObjectRequest(bucketName, itemName, newStream, metadata);
    _cos.putObject(req);

    System.out.printf("Item: %s created!\n", itemName);
}

請注意,在將自訂 meta 資料新增至物件時,必須使用 SDK 來建立 ObjectMetadata 物件,而不要手動傳送包含 x-amz-meta-{key} 的自訂標頭。 後者可能會在使用 HMAC 認證進行鑑別時造成問題。

從檔案上傳物件

此範例假設儲存區 sample 已存在。

cos.putObject(
    "sample", // the name of the destination bucket
    "myfile", // the object key
    new File("/home/user/test.txt") // the file name and path of the object to be uploaded
);

使用串流上傳物件

此範例假設儲存區 sample 已存在。

String obj = "An example"; // the object to be stored
ByteArrayOutputStream theBytes = new ByteArrayOutputStream(); // create a new output stream to store the object data
ObjectOutputStream serializer = new ObjectOutputStream(theBytes); // set the object data to be serialized
serializer.writeObject(obj); // serialize the object data
serializer.flush();
serializer.close();
InputStream stream = new ByteArrayInputStream(theBytes.toByteArray()); // convert the serialized data to a new input stream to store
ObjectMetadata metadata = new ObjectMetadata(); // define the metadata
metadata.setContentType("application/x-java-serialized-object"); // set the metadata
metadata.setContentLength(theBytes.size()); // set metadata for the length of the data stream
cos.putObject(
    "sample", // the name of the bucket to which the object is being written
    "serialized-object", // the name of the object being written
    stream, // the name of the data stream writing the object
    metadata // the metadata for the object being written
);

或者,您可以使用 CipherInputStream 來更輕鬆地加密資料串流,而不需要超載現有的 InputStream 物件。

public CipherInputStream encryptStream(InputStream inputStream) {
       // Generate key
       KeyGenerator kgen = KeyGenerator.getInstance("AES");
       kgen.init(128);
       SecretKey aesKey = kgen.generateKey();
       // Encrypt cipher
       Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
       cipher.init(Cipher.ENCRYPT_MODE, aesKey);
       CipherInputStream cis = new CipherInputStream(inputStream, cipher);
       return cis;
}

將物件下載至檔案

此範例假設儲存區 sample 已存在。

GetObjectRequest request = new // create a new request to get an object
GetObjectRequest( // request the new object by identifying
    "sample", // the name of the bucket
    "myFile" // the name of the object
);

s3Client.getObject( // write the contents of the object
    request, // using the request that was just created
    new File("retrieved.txt") // to write to a new file
);

使用串流下載物件

此範例假設儲存區 sample 已存在。

S3Object returned = cos.getObject( // request the object by identifying
    "sample", // the name of the bucket
    "serialized-object" // the name of the serialized object
);
S3ObjectInputStream s3Input = returned.getObjectContent(); // set the object stream

複製物件

// copy an object within the same Bucket
cos.copyObject( // copy the Object, passing…
    "sample",  // the name of the Bucket in which the Object to be copied is stored,
    "myFile.txt",  // the name of the Object being copied from the source Bucket,
    "sample",  // the name of the Bucket in which the Object to be copied is stored,
    "myFile.txt.backup"    // and the new name of the copy of the Object to be copied
);
// copy an object between two Buckets
cos.copyObject( // copy the Object, passing…
    "sample", // the name of the Bucket from which the Object will be copied,
    "myFile.txt", // the name of the Object being copied from the source Bucket,
    "backup", // the name of the Bucket to which the Object will be copied,
    "myFile.txt" // and the name of the copied Object in the destination Bucket
);

SDK 參照

類別

putObject 例外

即使新物件上傳成功,putObject 方法仍可能產生下列異常:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
    at com.ibm.cloud.objectstorage.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1597)
    at ibmcos.CoSExample.createTextFile(CoSExample.java:174)
    at ibmcos.CoSExample.main(CoSExample.java:65)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:499)
    ... 3 more

**主要原因:**會將 JAXB API 視為 Java EE API,且不再包含在 Java SE 9 的預設類別路徑上。

**修正:**將下列項目新增至您專案資料夾中的 pom.xml 檔案,並重新包裝專案。

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>

列出可用的儲存區

public static void getBuckets() {
    System.out.println("Retrieving list of buckets");

    final List<Bucket> bucketList = _cos.listBuckets();
    for (final Bucket bucket : bucketList) {
        System.out.printf("Bucket Name: %s\n", bucket.getName());
    }
}

SDK 參照

類別

方法

列出儲存區中的項目(第 2 版)

AmazonS3 物件包含用來列出內容的更新方法 (listObjectsV2)。 此方法可讓您限制傳回的記錄數,並分批次擷取記錄。 這可能有助於在應用程式內將您的結果進行分頁,並改善效能。

public static void getBucketContentsV2(String bucketName, int maxKeys) {
    System.out.printf("Retrieving bucket contents (V2) from: %s\n", bucketName);

    boolean moreResults = true;
    String nextToken = "";

    while (moreResults) {
        ListObjectsV2Request request = new ListObjectsV2Request()
            .withBucketName(bucketName)
            .withMaxKeys(maxKeys)
            .withContinuationToken(nextToken);

        ListObjectsV2Result result = _cos.listObjectsV2(request);
        for(S3ObjectSummary objectSummary : result.getObjectSummaries()) {
            System.out.printf("Item: %s (%s bytes)\n", objectSummary.getKey(), objectSummary.getSize());
        }
        if (result.isTruncated()) {
            nextToken = result.getNextContinuationToken();
            System.out.println("...More results in next batch!\n");
        }
        else {
            nextToken = "";
            moreResults = false;
        }
    }
    System.out.println("...No more results!");
}

SDK 參照

類別

方法

取得特定項目的檔案內容

public static void getItem(String bucketName, String itemName) {
    System.out.printf("Retrieving item from bucket: %s, key: %s\n", bucketName, itemName);

    S3Object item = _cos.getObject(new GetObjectRequest(bucketName, itemName));

    try {
        final int bufferSize = 1024;
        final char[] buffer = new char[bufferSize];
        final StringBuilder out = new StringBuilder();
        InputStreamReader in = new InputStreamReader(item.getObjectContent());

        for (; ; ) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0)
                break;
            out.append(buffer, 0, rsz);
        }

        System.out.println(out.toString());
    } catch (IOException ioe){
        System.out.printf("Error reading file %s: %s\n", name, ioe.getMessage());
    }
}

SDK 參照

類別

方法

從儲存區刪除項目

public static void deleteItem(String bucketName, String itemName) {
    System.out.printf("Deleting item: %s\n", itemName);
    _cos.deleteObject(bucketName, itemName);
    System.out.printf("Item: %s deleted!\n", itemName);
}

SDK 參照

方法

從儲存區刪除多個項目

刪除要求最多可以包含您要刪除的 1000 個金鑰。 雖然這對於降低每次要求的效能衝擊非常有用,但在刪除大量金鑰時請務必小心。 此外,也請考量物件的大小,以確保適當的效能。

public static void deleteItems(String bucketName) {
    DeleteObjectsRequest req = new DeleteObjectsRequest(bucketName);
    req.withKeys(
        "deletetest/testfile1.txt",
        "deletetest/testfile2.txt",
        "deletetest/testfile3.txt",
        "deletetest/testfile4.txt",
        "deletetest/testfile5.txt"
    );

    DeleteObjectsResult res = _cos.deleteObjects(req);

    System.out.printf("Deleted items for %s\n", bucketName);

    List<DeleteObjectsResult.DeletedObject> deletedItems = res.getDeletedObjects();
    for(DeleteObjectsResult.DeletedObject deletedItem : deletedItems) {
        System.out.printf("Deleted item: %s\n", deletedItem.getKey());
    }
}

SDK 參照

類別

方法

刪除儲存區

public static void deleteBucket(String bucketName) {
    System.out.printf("Deleting bucket: %s\n", bucketName);
    _cos.deleteBucket(bucketName);
    System.out.printf("Bucket: %s deleted!\n", bucketName);
}

SDK 參照

方法

檢查物件是否可公開讀取

public static void getItemACL(String bucketName, String itemName) {
    System.out.printf("Retrieving ACL for %s from bucket: %s\n", itemName, bucketName);

    AccessControlList acl = _cos.getObjectAcl(bucketName, itemName);

    List<Grant> grants = acl.getGrantsAsList();

    for (Grant grant : grants) {
        System.out.printf("User: %s (%s)\n", grant.getGrantee().getIdentifier(), grant.getPermission().toString());
    }
}

SDK 參照

類別

方法

執行多部分上傳

public static void multiPartUpload(String bucketName, String itemName, String filePath) {
    File file = new File(filePath);
    if (!file.isFile()) {
        System.out.printf("The file '%s' does not exist or is not accessible.\n", filePath);
        return;
    }

    System.out.printf("Starting multi-part upload for %s to bucket: %s\n", itemName, bucketName);

    InitiateMultipartUploadResult mpResult = _cos.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucketName, itemName));
    String uploadID = mpResult.getUploadId();

    //begin uploading the parts
    //min 5MB part size
    long partSize = 1024 * 1024 * 5;
    long fileSize = file.length();
    long partCount = ((long)Math.ceil(fileSize / partSize)) + 1;
    List<PartETag> dataPacks = new ArrayList<PartETag>();

    try {
        long position = 0;
        for (int partNum = 1; position < fileSize; partNum++) {
            partSize = Math.min(partSize, (fileSize - position));

            System.out.printf("Uploading to %s (part %s of %s)\n", name, partNum, partCount);

            UploadPartRequest upRequest = new UploadPartRequest()
                    .withBucketName(bucketName)
                    .withKey(itemName)
                    .withUploadId(uploadID)
                    .withPartNumber(partNum)
                    .withFileOffset(position)
                    .withFile(file)
                    .withPartSize(partSize);

            UploadPartResult upResult = _cos.uploadPart(upRequest);
            dataPacks.add(upResult.getPartETag());

            position += partSize;
        }

        //complete upload
        _cos.completeMultipartUpload(new CompleteMultipartUploadRequest(bucketName, itemName, uploadID, dataPacks));
        System.out.printf("Upload for %s Complete!\n", itemName);
    } catch (SdkClientException sdke) {
        System.out.printf("Multi-part upload aborted for %s\n", itemName);
        System.out.printf("Upload Error: %s\n", sdke.getMessage());
        _cos.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, itemName, uploadID));
    }
}

SDK 參照

類別

方法

建立備份政策

public static void main(String[] args) {
        try {
            // Initialize authenticator
            IamAuthenticator authenticator = new IamAuthenticator.Builder()
                    .apikey(API_KEY)
                    .build();

            // Initialize ResourceConfiguration client
            ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);

            // Generate unique backup vault name
            String backupVaultName = "vault-" + UUID.randomUUID().toString();

            // Create backup policy
            CreateBackupPolicyOptions backupPolicyOptions = new CreateBackupPolicyOptions.Builder()
                    .bucket(SOURCE_BUCKET_NAME)
                    .initialRetention(new DeleteAfterDays.Builder().deleteAfterDays(1).build())
                    .policyName(BACKUP_POLICY_NAME)
                    .targetBackupVaultCrn(BACKUP_VAULT_CRN)
                    .backupType("continuous").build();
            Response<BackupPolicy> createResult = rcClient.createBackupPolicy(backupPolicyOptions).execute();


            System.out.println("Policy Name:");
            System.out.println(createResult.getResult().getPolicyName());

        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        }
    }

列出備份政策

    public static void main(String[] args) {
            try {
                // Initialize IAM authenticator and Resource Configuration client
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);

                // List all backup policies
                ListBackupPoliciesOptions listOptions = new ListBackupPoliciesOptions.Builder()
                        .bucket(SOURCE_BUCKET_NAME)
                        .build();

                Response<BackupPolicyCollection> listResponse = rcClient.listBackupPolicies(listOptions).execute();

                System.out.println("\nList of backup policies:");
                List<?> policies = listResponse.getResult().getBackupPolicies();
                for (Object policy : policies) {
                    System.out.println(policy);
                }

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

取得備份政策

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);

                // Generate unique policy name
                String policyName = "policy_name_" + UUID.randomUUID().toString();


                // Fetch backup policy using policy ID
                GetBackupPolicyOptions getOptions = new GetBackupPolicyOptions.Builder()
                        .bucket(SOURCE_BUCKET_NAME)
                        .policyId(POLICY_ID)
                        .build();

                Response<BackupPolicy> getResponse = rcClient.getBackupPolicy(getOptions).execute();
                BackupPolicy fetchedPolicy = getResponse.getResult();

                System.out.println("\nFetched Backup Policy Details:");
                System.out.println(fetchedPolicy);

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

刪除備份原則

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);



                // Delete the created backup policy
                DeleteBackupPolicyOptions deleteOptions = new DeleteBackupPolicyOptions.Builder()
                        .bucket(SOURCE_BUCKET_NAME)
                        .policyId(POLICY_ID)
                        .build();

                rcClient.deleteBackupPolicy(deleteOptions).execute();

                System.out.printf("Backup policy '%s' deleted successfully.%n", POLICY_ID);

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

建立備份儲存庫

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);

                // Generate unique backup vault name
                String backupVaultName = "backup-vault-" + UUID.randomUUID();

                // Create backup vault
                CreateBackupVaultOptions createOptions = new CreateBackupVaultOptions.Builder()
                        .serviceInstanceId(SERVICE_INSTANCE_ID)
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .region(REGION)
                        .build();

                Response<BackupVault> response = rcClient.createBackupVault(createOptions).execute();
                BackupVault vault = response.getResult();

                System.out.println("Backup vault created:");
                System.out.println(vault);

            } catch (Exception e) {
                System.err.println("Error creating backup vault: " + e.getMessage());
                e.printStackTrace();
            }
        }

列出備份儲存庫

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);



                // List backup vaults

                ListBackupVaultsOptions listBackupVaultsOptions = new ListBackupVaultsOptions.Builder().
                        serviceInstanceId(SERVICE_INSTANCE_ID).build();
                Response<BackupVaultCollection> backupVaults = rcClient.listBackupVaults(listBackupVaultsOptions).execute();



                System.out.println("\nList of backup vaults:");
                if ( backupVaults.getResult().getBackupVaults() != null) {
                    for (String vault :  backupVaults.getResult().getBackupVaults()) {
                        System.out.println(vault);
                    }
                } else {
                    System.out.println("No backup vaults found.");
                }

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

取得備份儲存庫

    public static void main(String[] args) {
            try {
                // Initialize IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Create Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);

                // Generate unique backup vault name
                String backupVaultName = "backup-vault-" + UUID.randomUUID();


                // Get backup vault details
                GetBackupVaultOptions getOptions = new GetBackupVaultOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();

                Response<BackupVault> getResponse = rcClient.getBackupVault(getOptions).execute();
                BackupVault vaultDetails = getResponse.getResult();

                System.out.println("Backup vault details:");
                System.out.println(vaultDetails);

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

更新備份儲存庫

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);


                // Update vault: disable activity tracking and metrics monitoring

                BackupVaultPatch backupVaultPatch = new BackupVaultPatch.Builder()
                        .activityTracking(new BackupVaultActivityTracking.Builder().managementEvents(Boolean.FALSE).build())
                        .metricsMonitoring(new BackupVaultMetricsMonitoring.Builder().usageMetricsEnabled(Boolean.FALSE).build())
                        .build();
                UpdateBackupVaultOptions updateBackupVaultOptions = new UpdateBackupVaultOptions.Builder()
                        .backupVaultName(backupVaultName)
                        .backupVaultPatch(backupVaultPatch.asPatch()).build();
                Response<BackupVault> backupVaultResponse2 = rcClient.updateBackupVault(updateBackupVaultOptions).execute();


            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

刪除備份儲存庫

    public static void main(String[] args) {
            try {
                // Set up the authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);


                // Delete backup vault
                DeleteBackupVaultOptions deleteOptions = new DeleteBackupVaultOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();

                Response<Void> deleteResponse = rcClient.deleteBackupVault(deleteOptions).execute();
                System.out.println("Failed to delete backup vault '" + BACKUP_VAULT_NAME + "'.");

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

列名復原範圍

    public static void main(String[] args) {
            try {
                // Setup authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);



                // List recovery ranges
                ListRecoveryRangesOptions recoveryRangesOptions = new ListRecoveryRangesOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();

                Response<RecoveryRangeCollection> recoveryRangesResponse = rcClient.listRecoveryRanges(recoveryRangesOptions).execute();
                System.out.println("Recovery Ranges:");
                System.out.println(recoveryRangesResponse.getResult());

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

取得復原範圍

    public static void main(String[] args) {
            try {
                // Setup authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);


                // Fetch details of the recovery range
                GetSourceResourceRecoveryRangeOptions recoveryRangeOptions = new GetSourceResourceRecoveryRangeOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .recoveryRangeId(RECOVERY_RANGE_ID)
                        .build();

                Response<RecoveryRange> getRecoveryRangeResponse = rcClient.getSourceResourceRecoveryRange(recoveryRangeOptions).execute();
                System.out.println("Recovery Range Details:");
                System.out.println(getRecoveryRangeResponse.getResult());

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

更新復原範圍

    public static void main(String[] args) {
            try {
                // Setup authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);


                // Patch the recovery range (update retention to 99 days)
                PatchSourceResourceRecoveryRangeOptions patchOptions = new PatchSourceResourceRecoveryRangeOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .recoveryRangeId(RECOVERY_RANGE_ID)
                        .recoveryRangePatch(
                                new RecoveryRangePatch.Builder()
                                        .retention(new DeleteAfterDays.Builder().deleteAfterDays(99).build())
                                        .build()
                        )
                        .build();

                Response<RecoveryRange> patchResponse = rcClient.patchSourceResourceRecoveryRange(patchOptions).execute();
                System.out.println("Recovery Range successfully patched:");
                System.out.println(patchResponse.getResult());

            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

啟動還原

    public static void main(String[] args) {

            try {
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                ResourceConfiguration RC_CLIENT = new ResourceConfiguration("resource-configuration", authenticator);



                 CreateRestoreOptions  createRestoreOptions = new CreateRestoreOptions.Builder()
                         .backupVaultName(BACKUP_VAULT_NAME)
                         .recoveryRangeId(recoveryRangeId)
                         .restoreType("in_place")
                         .targetResourceCrn(TARGET_BUCKET_CRN)
                         .restorePointInTime(RESTORE_TIME)
                         .build();
                 Response<Restore> createRestoreCall = RC_CLIENT.createRestore(createRestoreOptions).execute();


                 String restoreId = createRestoreCall.getResult().getRestoreId();
                 GetRestoreOptions getRestoreOptions = new GetRestoreOptions.Builder().restoreId(restoreId).backupVaultName(backupVaultName).build();
                 Response<Restore> restoreResult = RC_CLIENT.getRestore(getRestoreOptions).execute();

                 System.out.println("Restore successfully:");
                 System.out.println(restoreResult);


            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

列名還原

    public static void main(String[] args) {

            try {
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                ResourceConfiguration RC_CLIENT = new ResourceConfiguration("resource-configuration", authenticator);



                ListRestoresOptions listRestoreOptions = new ListRestoresOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();

                Response<RestoreList> listRestoreResponse = rcClient.listRestores(listRestoreOptions).execute();
                System.out.println("Restore operations: " + listRestoreResponse.getResult());


           } catch (Exception e) {
               System.err.println("Error: " + e.getMessage());
               e.printStackTrace();
           }

        }

取得還原詳細資訊

    public static void main(String[] args) {

            try {
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();

                ResourceConfiguration RC_CLIENT = new ResourceConfiguration("resource-configuration", authenticator);


                Response<Restore> getRestoreOptions =
                        GetRestoreOptions.Builder()
                        .restoreId(restoreId)
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();
                Response<Restore> restoreResult = RC_CLIENT.getRestore(getRestoreOptions).execute();

                System.out.println("Get Restore: " + restoreResult);

           } catch (Exception e) {
               System.err.println("Error: " + e.getMessage());
               e.printStackTrace();
           }

        }

建立一個啟用物件鎖定功能的新 cos 儲存桶

    public static void createBucket(String bucketName, AmazonS3 _cosClient)
        {
            _cosClient.createBucket(bucketName);
            System.out.printf("Bucket: %s created!\n", bucketName);
        }

將物件鎖定設定與合規模式套用至 COS 儲存桶

    public static void putObjectLockConfiguration(String bucketName, AmazonS3 _cosClient)
        {
            DefaultRetention defRet = new DefaultRetention()
                    .withMode(ObjectLockRetentionMode.COMPLIANCE)
                    .withDays(1);
            ObjectLockRule objRule = new ObjectLockRule()
                            .withDefaultRetention(defRet);
            ObjectLockConfiguration objConfig = new ObjectLockConfiguration()
                            .withObjectLockEnabled(ObjectLockEnabled.ENABLED)
                            .withRule(objRule);
            SetObjectLockConfigurationRequest objSet = new SetObjectLockConfigurationRequest()
                            .withBucketName(BUCKET_NAME)
                            .withObjectLockConfiguration(objConfig);
            _cosClient.setObjectLockConfiguration(objSet);
            System.out.printf("Successfully added object lock cofiguration on : %s\n", bucketName);
        }

將物件鎖定設定與治理模式套用至 COS 儲存桶

    public static void putObjectLockConfigurationWithGovernanceMode(String bucketName, AmazonS3 _cosClient)
        {
            DefaultRetention defRet = new DefaultRetention()
                    .withMode(ObjectLockRetentionMode.GOVERNANCE)
                    .withDays(1);
            ObjectLockRule objRule = new ObjectLockRule()
                            .withDefaultRetention(defRet);
            ObjectLockConfiguration objConfig = new ObjectLockConfiguration()
                            .withObjectLockEnabled(ObjectLockEnabled.ENABLED)
                            .withRule(objRule);
            SetObjectLockConfigurationRequest objSet = new SetObjectLockConfigurationRequest()
                            .withBucketName(BUCKET_NAME)
                            .withObjectLockConfiguration(objConfig);
            _cosClient.setObjectLockConfiguration(objSet);
            System.out.printf("Successfully added object lock cofiguration on : %s\n", bucketName);
        }

取得 COS 儲存桶的物件鎖定設定

    public static void getObjectLockConfigurationWithGovernanceMode(String bucketName, AmazonS3 _cosClient)
        {
            GetObjectLockConfigurationRequest objReq = new GetObjectLockConfigurationRequest().withBucketName(BUCKET_NAME);
            GetObjectLockConfigurationResult objRes = _cosClient.getObjectLockConfiguration(objReq);
            ObjectLockConfiguration objLckConfig = objRes.getObjectLockConfiguration();
            ObjectLockRule objGetRule = objLckConfig.getRule();
            System.out.printf("ObjectLock Configuration : %s\n", objGetRule);

        }

將具有治理模式的物件上傳至 COS 儲存桶

    public static void uploadFileWithGovernanceMode(String bucketName, String itemName, String fileText) {
            System.out.printf("Creating new item: %s\n", itemName);
            LocalDate date = LocalDate.of(2025, 11, 11);
            InputStream newStream = new ByteArrayInputStream(fileText.getBytes(Charset.forName("UTF-8")));
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(fileText.length());
            PutObjectRequest req = new PutObjectRequest(bucketName, itemName, newStream, metadata)
                                .withObjectLockMode("GOVERNANCE")
                                .withObjectLockRetainUntilDate(date);
            _cosClient.putObject(req);
            System.out.printf("Item: %s created!\n", itemName);
        }

在物件上啟用物件鎖保留與合規模式

    public static void putObjectLockRetention(String bucketName,String itemName, AmazonS3 _cosClient)
        {
            LocalDate date = LocalDate.of(2025, 11, 11);
            ObjectLockRetention objRet = new ObjectLockRetention()
                        .withMode("COMPLIANCE")
                        .withRetainUntilDate(date);
            SetObjectRetentionRequest objSet = new SetObjectRetentionRequest()
                        .withBucketName(BUCKET_NAME)
                        .withitemName(itemName)
                        .withRetention(objRet);
                        .withBypassGovernanceRetention(true);
            _cosClient.setObjectRetention(objSet);
            System.out.printf("Successfully added object retention on : %s\n", itemName);
        }

在物件上啟用物件鎖保留與治理模式

    public static void putObjectLockRetentionWithGovernanceMode(String bucketName,String itemName, AmazonS3 _cosClient)
        {
            LocalDate date = LocalDate.of(2025, 11, 11);
            ObjectLockRetention objRet = new ObjectLockRetention()
                        .withMode("GOVERNANCE")
                        .withRetainUntilDate(date);
            SetObjectRetentionRequest objSet = new SetObjectRetentionRequest()
                        .withBucketName(BUCKET_NAME)
                        .withitemName(itemName)
                        .withRetention(objRet);
                        .withBypassGovernanceRetention(true);
            _cosClient.setObjectRetention(objSet);
            System.out.printf("Successfully added object retention on : %s\n", itemName);
        }

取得物件鎖保留

    public static void getObjectLockRetentionWithGovernanceMode(String bucketName,String itemName, AmazonS3 _cosClient)
        {
            GetObjectRetentionRequest objReq = new GetObjectRetentionRequest()
                .withBucketName(BUCKET_NAME)
                .withitemName(itemName);
            GetObjectRetentionResult objRes1 = _cosClient.getObjectRetention(objReq);
            ObjectLockRetention objRet1 = objRes1.getRetention();
            System.out.printf("Retention : %s\n", objRet1);
        }

使用繞過治理刪除具有物件鎖治理模式的物件

    public static void deleteObjectWithBypassGovernance(String bucketName, String itemName) {
            System.out.printf("Deleting item: %s\n", itemName);
            DeleteObjectRequest deleteRequest = new DeleteObjectRequest(BUCKET_NAME, Key)
                .withBypassGovernanceRetention(true);
            _cosClient.deleteObject(deleteRequest);
            System.out.printf("Item: %s deleted!\n", itemName);
        }

使用 Transfer Manager 上傳較大的物件

TransferManager 可簡化大型檔案傳送,方法是在必須設定配置參數時自動併入多部分上傳。

public static void largeObjectUpload(String bucketName, String itemName, String filePath) throws IOException, InterruptedException {
    File uploadFile = new File(filePath);

    if (!uploadFile.isFile()) {
        System.out.printf("The file '%s' does not exist or is not accessible.\n", filePath);
        return;
    }

    System.out.println("Starting large file upload with TransferManager");

    //set the part size to 5 MB
    long partSize = 1024 * 1024 * 5;

    //set the threshold size to 5 MB
    long thresholdSize = 1024 * 1024 * 5;

    String endPoint = getEndpoint(COS_BUCKET_LOCATION, "public");
    AmazonS3 s3client = createClient(COS_API_KEY_ID, COS_SERVICE_CRN, endPoint, COS_BUCKET_LOCATION);

    TransferManager transferManager = TransferManagerBuilder.standard()
        .withS3Client(s3client)
        .withMinimumUploadPartSize(partSize)
        .withMultipartCopyThreshold(thresholdSize)
        .build();

    try {
        Upload lrgUpload = transferManager.upload(bucketName, itemName, uploadFile);

        lrgUpload.waitForCompletion();

        System.out.println("Large file upload complete!");
    }
    catch (SdkClientException e) {
        System.out.printf("Upload error: %s\n", e.getMessage());
    }
    finally {
        transferManager.shutdownNow();
    }

SDK 參照

類別

方法

使用 Key Protect

Key Protect 可新增至儲存空間儲存區,以加密雲端中靜止的機密資料。

開始之前

為了建立儲存區並啟用 Key Protect,需要下列項目:

擷取根金鑰 CRN

  1. 擷取 Key Protect 服務的實例 ID
  2. 使用 Key Protect API 來擷取所有可用金鑰
  3. 擷取您將使用來在儲存區上啟用 Key Protect 的根金鑰 CRN。 CRN 看起來如下:

crn:v1:bluemix:public:kms:us-south:a/3d624cd74a0dea86ed8efe3101341742:90b6a1db-0fe1-4fe9-b91e-962c327df531:key:0bg3e33e-a866-50f2-b715-5cba2bc93234

建立儲存區並啟用 key-protect

private static String COS_KP_ALGORITHM = "<algorithm>";
private static String COS_KP_ROOTKEY_CRN = "<root-key-crn>";

public static void createBucketKP(String bucketName) {
    System.out.printf("Creating new encrypted bucket: %s\n", bucketName);

    EncryptionType encType = new EncryptionType();
    encType.setKmsEncryptionAlgorithm(COS_KP_ALGORITHM);
    encType.setIBMSSEKMSCustomerRootKeyCrn(COS_KP_ROOTKEY_CRN);

    CreateBucketRequest req = new CreateBucketRequest(bucketName).withEncryptionType(encType);

    _cos.createBucket(req);

    System.out.printf("Bucket: %s created!", bucketName);
}

金鑰值

  • <algorithm>- 新增到資料桶的新物件所使用的加密演算法 (預設為 AES256 )。
  • <root-key-crn>- 從 Key Protect 服務取得的 Root Key 的 CRN。

SDK 參照

類別

方法

Key Protect 的新標頭

其他標頭已定義在 Headers 類別內:

public static final String IBM_SSE_KP_ENCRYPTION_ALGORITHM = "ibm-sse-kp-encryption-algorithm";
public static final String IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN = "ibm-sse-kp-customer-root-key-crn";

已新增 IAM 服務實例標頭之建立儲存區實作的相同區段中,將會新增 2 個新的加密標頭:

//Add IBM Service Instance Id & Encryption to headers
if ((null != this.awsCredentialsProvider ) && (this.awsCredentialsProvider.getCredentials() instanceof IBMOAuthCredentials)) {
    IBMOAuthCredentials oAuthCreds = (IBMOAuthCredentials)this.awsCredentialsProvider.getCredentials();
    if (oAuthCreds.getServiceInstanceId() != null) {
        request.addHeader(Headers.IBM_SERVICE_INSTANCE_ID, oAuthCreds.getServiceInstanceId());
        request.addHeader(Headers.IBM_SSE_KP_ENCRYPTION_ALGORITHM, createBucketRequest.getEncryptionType().getKpEncryptionAlgorithm());
        request.addHeader(Headers.IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN, createBucketRequest.getEncryptionType().getIBMSSEKPCustomerRootKeyCrn());
    }
}

ObjectListingHeadBucketResult 物件已更新為包含有 getter 和 setter 方法的 boolean IBMSSEKPEnabled 和 String IBMSSEKPCustomerRootKeyCrn 變數。 這些將會儲存新標頭的值。

GET 儲存區

public ObjectListing listObjects(String bucketName)
public ObjectListing listObjects(String bucketName, String prefix)
public ObjectListing listObjects(ListObjectsRequest listObjectsRequest)

ObjectListing 類別需要 2 個額外的方法:

ObjectListing listing = s3client.listObjects(listObjectsRequest)
String KPEnabled = listing.getIBMSSEKPEnabled();
String crkId = listing.getIBMSSEKPCrkId();

附加標頭已在 Headers 類別中定義:

Headers.java
public static final string IBM_SSE_KP_ENABLED = "ibm-sse-kp-enabled";
public static final String IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN = "ibm-sse-kp-customer-root-key-crn";

S3XmlResponseHandler 負責取消配置所有 XML 回應。 已新增檢查,其結果是 ObjectListing 的實例,而擷取的標頭將新增至 ObjectListing 物件:

if (result instanceof ObjectListing) {
    if (!StringUtils.isNullOrEmpty(responseHeaders.get(Headers.IBM_SSE_KP_ENABLED)){
            ((ObjectListing) result).setIBMSSEKPEnabled(Boolean.parseBoolean(responseHeaders.get(Headers.IBM_SSE_KP_ENABLED)));
        }
    if (!StringUtils.isNullOrEmpty(responseHeaders.get(Headers.IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN))) {
            ((ObjectListing) result).setIBMSSEKPCrk(responseHeaders.get(Headers.IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN));
        }
}

HEAD 儲存區

其他標頭已定義在 Headers 類別內:

Headers.java
public static final String IBM_SSE_KP_ENABLED = "ibm-sse-kp-enabled";
public static final String IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN = "ibm-sse-kp-customer-root-key-crn";

這些變數會移入 HeadBucketResponseHandler 中。

HeadBucketResultHandler
result.setIBMSSEKPEnabled(response.getHeaders().get(Headers.IBM_SSE_KP_ENABLED));
result.setIBMSSEKPCrk(response.getHeaders().get(Headers. IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN));

Head Bucket Example
HeadBucketResult result = s3client.headBucket(headBucketRequest)
boolean KPEnabled = result.getIBMSSEKPEnabled();
String crn = result.getIBMSSEKPCUSTOMERROOTKEYCRN();

使用 Aspera 高速傳輸

透過安裝 Aspera 高速傳送程式庫,您可以在應用程式中使用高速檔案傳送。 Aspera 程式庫是封閉的來源,因此對於 COS SDK(其使用 Apache 授權)具有選用的相依關係。

每一個 Aspera 高速傳送階段作業都會產生在用戶端機器上執行的個別 ascp 處理程序,以執行傳送。 請確定您的運算環境可以容許執行此處理程序。

您將需要 S3 Client 及 IAM Token Manager 類別的實例,才能起始設定 AsperaTransferManager。 需要 s3Client,才能取得 COS 目標儲存區的 FASP 連線資訊。 需要 tokenManager,才能容許 Aspera 高速傳送 SDK,以使用 COS 目標儲存區進行鑑別。

起始設定 AsperaTransferManager

在起始設定 AsperaTransferManager 之前,請確定您已使用 s3ClienttokenManager 物件。

使用 AsperaTransferManagerBuilder 建置 AsperaTransferManager 時,建議使用 TokenManager tokenManager = new DefaultTokenManager(new DelegateTokenProvider(apiKey)); 並避免使用 .withTokenManager(tokenManager)

除非您預期在網路中看到大量的雜訊或封包流失,否則使用 Aspera 高速傳送的單一階段作業不會有多大的好處。 因此,我們需要告知 AsperaTransferManager 使用 AsperaConfig 類別,以使用多個階段作業。 這會將傳送分割成數個平行的階段作業 ,以傳送大小由 threshold 值定義的資料區塊。

使用多個階段作業的一般配置應該是:

  • 2500 MBps 目標率
  • 100 MB 臨界值(此為大部分應用程式的建議值
AsperaTransferManagerConfig transferConfig = new AsperaTransferManagerConfig()
    .withMultiSession(true);

AsperaConfig asperaConfig = new AsperaConfig()
    .withTargetRateMbps(2500L)
    .withMultiSessionThresholdMb(100);

TokenManager tokenManager = new DefaultTokenManager(new DelegateTokenProvider(API_KEY));

AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client)
    .withAsperaTransferManagerConfig(transferConfig)
    .withAsperaConfig(asperaConfig)
    .build();

在上述範例中,SDK 會大量產生足夠的階段作業,以嘗試達到目標率 2500 MBps。

或者,可以在 SDK 中明確配置階段作業管理。 在需要更精確控制網路使用率的情況下,這十分有用。

使用明確的多個階段作業的一般配置應該是:

  • 2 或 10 個階段作業
  • 100 MB 臨界值(此為大部分應用程式的建議值
AsperaConfig asperaConfig = new AsperaConfig()
    .withMultiSession(2)
    .withMultiSessionThresholdMb(100);

TokenManager tokenManager = new DefaultTokenManager(new DelegateTokenProvider(API_KEY));

AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client)
    .withAsperaConfig(asperaConfig)
    .build();

為了在大多數情況下獲得最佳效能,請務必使用多個階段,以盡量減少與實體化 Aspera 高速傳輸相關的任何處理。 如果您的網路容量至少為 1 Gbps,您應該使用 10 個階段作業。 較低頻寬的網路應該使用兩個階段作業。

金鑰值

  • API_KEY - 具有「撰寫者」或「管理者」角色之使用者或服務 ID 的 API 金鑰

您需要提供 IAM API 金鑰,才能建構 AsperaTransferManager。 目前 支援 HMAC 認證。 如需 IAM 的相關資訊,請按一下這裡

檔案上傳

String filePath = "<absolute-path-to-source-data>";
String bucketName = "<bucket-name>";
String itemName = "<item-name>";

// Load file
File inputFile = new File(filePath);

// Create AsperaTransferManager for FASP upload
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client).build();

// Upload test file and report progress
Future<AsperaTransaction> asperaTransactionFuture = asperaTransferMgr.upload(bucketName, itemName, inputFile);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- Object Storage 服務實例中已啟用 Aspera 的儲存桶名稱。
  • <absolute-path-to-source-data>- 目錄和檔案名稱上傳至 Object Storage。
  • <item-name>- 新增到水桶的新物件的名稱。

檔案下載

String bucketName = "<bucket-name>";
String outputPath = "<absolute-path-to-file>";
String itemName = "<item-name>";

// Create local file
File outputFile = new File(outputPath);
outputFile.createNewFile();

// Create AsperaTransferManager for FASP download
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, s3Client)
    .withTokenManager(tokenManager)
    .withAsperaConfig(asperaConfig)
    .build();

// Download file
Future<AsperaTransaction> asperaTransactionFuture = asperaTransferMgr.download(bucketName, itemName, outputPath);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- Object Storage 服務實例中已啟用 Aspera 的儲存桶名稱。
  • <absolute-path-to-file>- 從 Object Storage 儲存的目錄和檔案名稱。
  • <item-name>- 水桶中物件的名稱。

目錄上傳

String bucketName = "<bucket-name>";
String directoryPath = "<absolute-path-to-directory-for-new-file>";
String directoryPrefix = "<virtual-directory-prefix>";
boolean includeSubDirectories = true;

// Load Directory
File inputDirectory = new File(directoryPath);

// Create AsperaTransferManager for FASP upload
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, s3Client)
    .withTokenManager(tokenManager)
    .withAsperaConfig(asperaConfig)
    .build();

// Upload test directory
Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.uploadDirectory(bucketName, directoryPrefix, inputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- Object Storage 服務實例中已啟用 Aspera 的儲存桶名稱。
  • <absolute-path-to-directory>- 目錄中的檔案上傳至 Object Storage。
  • <virtual-directory-prefix>- 上傳時要加入每個檔案的目錄前綴名稱。 請使用空值或空字串,將檔案上傳至儲存區根目錄。

目錄下載

String bucketName = "<bucket-name>";
String directoryPath = "<absolute-path-to-directory>";
String directoryPrefix = "<virtual-directory-prefix>";
boolean includeSubDirectories = true;

// Load Directory
File outputDirectory = new File(directoryPath);

// Create AsperaTransferManager for FASP download
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, s3Client)
    .withTokenManager(tokenManager)
    .withAsperaConfig(asperaConfig)
    .build();

// Download test directory
Future<AsperaTransaction> asperaTransactionFuture   = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- Object Storage 服務實例中已啟用 Aspera 的儲存桶名稱。
  • <absolute-path-to-directory>- 目錄來儲存從 Object Storage 下載的檔案。
  • <virtual-directory-prefix>- 要下載的每個檔案的目錄前綴名稱。 請使用空值或空字串,以下載儲存區中的所有檔案。

在每個傳送基礎上置換階段作業配置

在每個傳送基礎上,您可以透過將 AsperaConfig 的實例傳遞至上傳及下載已置換方法,來置換多階段作業配置值。 使用 AsperaConfig,您可以指定階段作業數及每個階段作業的檔案臨界值大小下限。

String bucketName = "<bucket-name>";
String filePath = "<absolute-path-to-file>";
String itemName = "<item-name>";

// Load file
File inputFile = new File(filePath);

// Create AsperaTransferManager for FASP upload
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client)
.withTokenManager(TOKEN_MANAGER)
.withAsperaConfig(asperaConfig)
.build();

// Create AsperaConfig to set number of sessions
// and file threshold per session.
AsperaConfig asperaConfig = new AsperaConfig().
withMultiSession(10).
withMultiSessionThresholdMb(100);

// Upload test file and report progress
Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.upload(bucketName, itemName, inputFile, asperaConfig, null);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

監視傳送進度

監視檔案/目錄傳送進度的最簡單方式是使用 isDone() 內容,當您的傳送完成時,會傳回 true

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

while (!asperaTransaction.isDone()) {
    System.out.println("Directory download is in progress");

    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

您也可以在 AsperaTransaction 上呼叫 onQueue 方法,以檢查傳送是否已排入佇列等待處理。onQueue 會傳回一個布林,其中含有 true,指出傳送已排入佇列。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

while (!asperaTransaction.isDone()) {
    System.out.println("Directory download is in queueing: " + asperaTransaction.onQueue());

    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

若要檢查傳送是否正在進行,請在 AsperaTransaction 中呼叫進度方法。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

while (!asperaTransaction.isDone()) {
    System.out.println("Directory download is in progress: " + asperaTransaction.progress());

    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

依預設,每個傳送都會有 TransferProgress 附加至其中。 TransferProgress 會報告傳送的位元組數,以及要傳送的位元組總數的傳送百分比。 若要存取傳送的 TransferProgress,請在 getProgress 中使用 AsperaTransaction 方法。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

while (!asperaTransaction.isDone()) {
    TransferProgress transferProgress = asperaTransaction.getProgress();

    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

若要報告傳送的位元組數,請在 getBytesTransferred上呼叫 TransferProgress 方法。 若要報告傳送的位元組總數傳送百分比,請在 getPercentTransferred 上呼叫 TransferProgress 方法。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

while (!asperaTransaction.isDone()) {
    TransferProgress transferProgress = asperaTransaction.getProgress();

    System.out.println("Bytes transferred: " + transferProgress.getBytesTransferred());
    System.out.println("Percent transferred: " + transferProgress.getPercentTransferred());


    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

暫停/繼續/取消

SDK 可讓您透過 AsperaTransfer 物件的下列方法來管理檔案/目錄傳送的進度:

  • pause()
  • resume()
  • cancel()

呼叫上述任一種方法時,不會產生任何副作用。 SDK 會處理適當的清除及整理。

下列範例顯示這些方法的可能用法:

String bucketName = "<bucket-name>";
String directoryPath = "<absolute-path-to-directory>";
String directoryPrefix = "<virtual-directory-prefix>";
boolean includeSubDirectories = true;

AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, _cos)
    .withTokenManager(TOKEN_MANAGER)
    .build();

File outputDirectory = new File(directoryName);

System.out.println("Starting directory download...");

//download the directory from cloud storage
Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

int pauseCount = 0;

while (!asperaTransaction.isDone()) {
    System.out.println("Directory download in progress...");

    //pause the transfer
    asperaTransfer.pause();

    //resume the transfer
    asperaTransfer.resume();

    //cancel the transfer
    asperaTransfer.cancel();
}

System.out.println("Directory download complete!");

疑難排解 Aspera 問題

**問題:**在 Linux 或 Mac OS X 上使用 Oracle JDK 的開發人員在傳送期間可能會遇到非預期且無聲自動的損毀

**原因:**原生程式碼需要它自己的信號處理程式,這可能會置換 JVM 的信號處理程式。 可能需要使用 JVM 的信號鏈結機能。

IBM® JDK 使用者或 Microsoft® Windows 使用者不受影響。

**解決方案:**鏈結並載入 JVM 的信號鏈結程式庫。

  • 在 Linux 上尋找 libjsig.so 共用程式庫,並設定下列環境變數:

    • LD_PRELOAD=<PATH_TO_SHARED_LIB>/libjsig.so
  • 在 Mac OS X 上,尋找共用程式庫 libjsig.dylib,並設定下列環境變數:

    • DYLD_INSERT_LIBRARIES=<PATH_TO_SHARED_LIB>/libjsig.dylib
    • DYLD_FORCE_FLAT_NAMESPACE=0

請造訪 Oracle® JDK 文件,取得更多關於訊號鏈的資訊。

**問題:**Linux 上的 UnsatisfiedLinkError

**原因:**系統無法載入相依程式庫。 在應用程式日誌中,可能會看到下列錯誤:

libfaspmanager2.so: libawt.so: cannot open shared object file: No such file or directory

**解決方案:**設定下列環境變數:

LD_LIBRARY_PATH=<JAVA_HOME>/jre/lib/amd64/server:<JAVA_HOME>/jre/lib/amd64

更新 meta 資料

有兩種方式可更新現有物件上的 meta 資料:

  • 具有新 meta 資料及原始物件內容的 PUT 要求
  • 使用新 meta 資料來執行 COPY 要求,並指定原始物件作為副本來源

使用 PUT 更新 meta 資料

PUT 請求會覆蓋物件的現有內容,因此必須先下載,然後再以新的元資料重新上傳。

public static void updateMetadataPut(String bucketName, String itemName, String key, String value) throws IOException {
    System.out.printf("Updating metadata for item: %s\n", itemName);

    //retrieve the existing item to reload the contents
    S3Object item = _cos.getObject(new GetObjectRequest(bucketName, itemName));
    S3ObjectInputStream itemContents = item.getObjectContent();

    //read the contents of the item in order to set the content length and create a copy
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    int b;
    while ((b = itemContents.read()) != -1) {
        output.write(b);
    }

    int contentLength = output.size();
    InputStream itemCopy = new ByteArrayInputStream(output.toByteArray());

    //set the new metadata
    HashMap<String, String> userMetadata = new HashMap<String, String>();
    userMetadata.put(key, value);

    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(contentLength);
    metadata.setUserMetadata(userMetadata);

    PutObjectRequest req = new PutObjectRequest(bucketName, itemName, itemCopy, metadata);

    _cos.putObject(req);

    System.out.printf("Updated metadata for item %s from bucket %s\n", itemName, bucketName);
}

使用 COPY 更新 meta 資料

public static void updateMetadataCopy(String bucketName, String itemName, String key, String value) {
    System.out.printf("Updating metadata for item: %s\n", itemName);

    //set the new metadata
    HashMap<String, String> userMetadata = new HashMap<String, String>();
    userMetadata.put(key, value);

    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setUserMetadata(userMetadata);

    //set the copy source to itself
    CopyObjectRequest req = new CopyObjectRequest(bucketName, itemName, bucketName, itemName);
    req.setNewObjectMetadata(metadata);

    _cos.copyObject(req);

    System.out.printf("Updated metadata for item %s from bucket %s\n", itemName, bucketName);
}

使用 Immutable Object Storage

將保護配置新增至現有儲存區

PUT 作業的實作使用 protection 查詢參數來設定現有儲存區的保留參數。 此作業可讓您設定或變更最短保留期間、預設值及最長保留期間。 此作業也可讓您變更儲存區的保護狀態。

在保護期間過期,並移除物件上的所有合法保留之前,無法刪除寫入受保護儲存區的物件。 除非在物件建立時提供物件特定值,否則會將儲存區的預設保留值提供給物件。 不再保留的受保護儲存區物件(保留期間已過期,而物件沒有任何合法保留),在被改寫時會再次保留。 新的保留期間可以提供為物件改寫要求的一部分,否則會將儲存區的預設保留時間提供給物件。

保留期間設定 MinimumRetentionDefaultRetentionMaximumRetention 的最小及最大支援值為 0 天及 365243 天 (1000 年)。

public static void addProtectionConfigurationToBucket(String bucketName) {
    System.out.printf("Adding protection to bucket: %s\n", bucketName);

    BucketProtectionConfiguration newConfig = new BucketProtectionConfiguration()
        .withStatus(BucketProtectionStatus.Retention)
        .withMinimumRetentionInDays(10)
        .withDefaultRetentionInDays(100)
        .withMaximumRetentionInDays(1000);

    cos.setBucketProtection(bucketName, newConfig);

    System.out.printf("Protection added to bucket %s\n", bucketName);
}

public static void addProtectionConfigurationToBucketWithRequest(String bucketName) {
    System.out.printf("Adding protection to bucket: %s\n", bucketName);

    BucketProtectionConfiguration newConfig = new BucketProtectionConfiguration()
        .withStatus(BucketProtectionStatus.Retention)
        .withMinimumRetentionInDays(10)
        .withDefaultRetentionInDays(100)
        .withMaximumRetentionInDays(1000);

    SetBucketProtectionConfigurationRequest newRequest = new SetBucketProtectionConfigurationRequest()
        .withBucketName(bucketName)
        .withProtectionConfiguration(newConfig);

    cos.setBucketProtectionConfiguration(newRequest);

    System.out.printf("Protection added to bucket %s\n", bucketName);
}

檢查儲存區的保護

public static void getProtectionConfigurationOnBucket(String bucketName) {
    System.out.printf("Retrieving protection configuration from bucket: %s\n", bucketName;

    BucketProtectionConfiguration config = cos.getBucketProtection(bucketName);

    String status = config.getStatus();

    System.out.printf("Status: %s\n", status);

    if (!status.toUpperCase().equals("DISABLED")) {
        System.out.printf("Minimum Retention (Days): %s\n", config.getMinimumRetentionInDays());
        System.out.printf("Default Retention (Days): %s\n", config.getDefaultRetentionInDays());
        System.out.printf("Maximum Retention (Days): %s\n", config.getMaximumRetentionInDays());
    }
}

上傳受保護物件

不再保留的受保護儲存區物件(保留期間已過期,而物件沒有任何合法保留),在被改寫時會再次保留。 新的保留期間可以提供為物件改寫要求的一部分,否則會將儲存區的預設保留時間提供給物件。

類型 說明
Retention-Period 非負整數(秒) 儲存在物件上的保留期間(以秒為單位)。 除非已過保留期間中指定的時間,否則無法改寫或刪除物件。 如果指定此欄位及 Retention-Expiration-Date,則會傳回 400 錯誤。 如果未指定任一項,則會使用儲存區的 DefaultRetention 期間。 零 (0) 是合法值,假設儲存區最小保留期間也為 0
Retention-expiration-date 日期(ISO 8601 格式) 在此日期將可以合法刪除或修改物件。 您只能指定此項或 Retention-Period 標頭。 如果兩者都指定,則會傳回 400 錯誤。 如果未指定任一項,則會使用儲存區的 DefaultRetention 期間。
Retention-legal-hold-id 字串 要套用至物件的單一合法保留。 合法保留是 Y 字元長字串。 除非已移除與物件相關聯的所有合法保留,否則無法改寫或刪除物件。
public static void putObjectAddLegalHold(String bucketName, String objectName, String fileText, String legalHoldId) {
    System.out.printf("Add legal hold %s to %s in bucket %s with a putObject operation.\n", legalHoldId, objectName, bucketName);

    InputStream newStream = new ByteArrayInputStream(fileText.getBytes(StandardCharsets.UTF_8));

    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(fileText.length());

    PutObjectRequest req = new PutObjectRequest(
        bucketName,
        objectName,
        newStream,
        metadata
    );
    req.setRetentionLegalHoldId(legalHoldId);

    cos.putObject(req);

    System.out.printf("Legal hold %s added to object %s in bucket %s\n", legalHoldId, objectName, bucketName);
}

public static void copyProtectedObject(String sourceBucketName, String sourceObjectName, String destinationBucketName, String newObjectName) {
    System.out.printf("Copy protected object %s from bucket %s to %s/%s.\n", sourceObjectName, sourceBucketName, destinationBucketName, newObjectName);

    CopyObjectRequest req = new CopyObjectRequest(
        sourceBucketName,
        sourceObjectName,
        destinationBucketName,
        newObjectName
    );
    req.setRetentionDirective(RetentionDirective.COPY);


    cos.copyObject(req);

    System.out.printf("Protected object copied from %s/%s to %s/%s\n", sourceObjectName, sourceBucketName, destinationBucketName, newObjectName);
}

延長受保護物件的保留期間

只能延長物件的保留期間。 不能從目前配置的值縮短。

保留擴充值以三種方式之一來設定:

  • 現行值再加上時間(Additional-Retention-Period 或類似方法)
  • 新擴充期間(以秒為單位)(Extend-Retention-From-Current-Time 或類似方法)
  • 物件的新保留到期日(New-Retention-Expiration-Date 或類似方法)

儲存在物件 meta 資料中的現行保留期間,會增加給定的額外時間,或以新值取代,視 extendRetention 要求中設定的參數而定。 在所有情況下,會針對現行保留期間檢查延長保留參數,而且只有在更新的保留期間大於現行保留期間時,才會接受延長的參數。

不再保留的受保護儲存區物件(保留期間已過期,而物件沒有任何合法保留),在被改寫時會再次保留。 新的保留期間可以提供為物件改寫要求的一部分,否則會將儲存區的預設保留時間提供給物件。

public static void extendRetentionPeriodOnObject(String bucketName, String objectName, Long additionalSeconds) {
    System.out.printf("Extend the retention period on %s in bucket %s by %s seconds.\n", objectName, bucketName, additionalSeconds);

    ExtendObjectRetentionRequest req = new ExtendObjectRetentionRequest(
        bucketName,
        objectName)
        .withAdditionalRetentionPeriod(additionalSeconds);

    cos.extendObjectRetention(req);

    System.out.printf("New retention period on %s is %s\n", objectName, additionalSeconds);
}

列出受保護物件的合法保留

此作業傳回:

  • 物件建立日期
  • 物件保留期間(秒)
  • 根據期間和建立日期計算的保留到期日
  • 合法保留的清單
  • 合法保留 ID
  • 套用合法保留時的時間戳記

如果物件沒有任何合法保留,則會傳回空的 LegalHoldSet。 如果在物件上未指定保留期間,則會傳回 404 錯誤。

public static void listLegalHoldsOnObject(String bucketName, String objectName) {
    System.out.printf("List all legal holds on object %s in bucket %s\n", objectName, bucketName);

    ListLegalHoldsResult result = cos.listLegalHolds(
        bucketName,
        objectName
    );

    System.out.printf("Legal holds on bucket %s: \n", bucketName);

    List<LegalHold> holds = result.getLegalHolds();
    for (LegalHold hold : holds) {
        System.out.printf("Legal Hold: %s", hold);
    }
}

建立代管的靜態網站

這項作業需要新增 import 陳述式:

import com.ibm.cloud.objectstorage.services.s3.model.model.BucketWebsiteConfiguration;

此作業在配置時提供下列項目,且需要正確配置的用戶端:

  • 字尾 (索引文件) 的儲存區配置
  • 金鑰的儲存區配置 (錯誤文件)
cosClient.setBucketWebsiteConfiguration("<bucket_name>", new BucketWebsiteConfiguration("index.html", "error.html"));

後續步驟

如需相關資訊,請參閱 Javadoc。 您可以在 GitHub 儲存庫中找到專案的原始碼。