1. 概要

このチュートリアルでは、JetS3tライブラリをAmazonS3で使用します。

簡単に言うと、バケットを作成し、データを書き込み、データを読み戻し、コピーしてから、バケットを一覧表示して削除します。

2. JetS3tのセットアップ

2.1. Mavenの依存関係

まず、NATSライブラリと ApacheHttpClientpom.xmlに追加する必要があります。

<dependency>
    <groupId>org.lucee</groupId>
    <artifactId>jets3t</artifactId>
    <version>0.9.4.0006L</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.5</version>
</dependency>

Maven Centralには、最新バージョンのJetS3tライブラリ最新バージョンのHttpClientがあります。 JetS3tのソースは、ここにあります。

テストの1つにApacheCommons Codec を使用するので、それをpom.xmlにも追加します。

<dependency>
    <groupId>org.lucee</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10.L001</version>
</dependency>

MavenCentralには最新バージョンここがあります。

2.2. アマゾンAWSキー

S3ストレージサービスに接続するにはAWSアクセスキーが必要です。ここで無料のアカウントを作成できます。

アカウントを取得したら、セキュリティキーのセットを作成する必要があります。ユーザーとアクセスキーに関するドキュメントがここにあります。

JetS3tはApacheCommonsロギングを使用しているため、実行中の情報を印刷する場合にも使用します。

3. シンプルなストレージへの接続

AWSアクセスキーとシークレットキーができたので、S3ストレージに接続できます。

3.1. AWSへの接続

まず、AWSクレデンシャルを作成し、それを使用してサービスに接続します。

AWSCredentials awsCredentials 
  = new AWSCredentials("access key", "secret key");
s3Service = new RestS3Service(awsCredentials);

RestS3ServiceはAmazonS3への接続です。HttpClientを使用してRESTを介してS3と通信します。

3.2. 接続の確認

バケットを一覧表示することで、サービスに正常に接続したことを確認できます。

S3Bucket[] myBuckets = s3Service.listAllBuckets();

以前にバケットを作成したかどうかによっては、配列が空になる場合がありますが、操作で例外がスローされない場合は、有効な接続があります。

4. バケット管理

Amazon S3に接続すると、データを保持するためのバケットを作成できます。 S3はオブジェクトストレージシステムです。 データはオブジェクトとしてアップロードされ、バケットに保存されます。

すべてのS3バケットは同じグローバル名前空間を共有するため、それぞれに一意の名前を付ける必要があります。

4.1. バケットの作成

バケット名「mybucket」を作成してみましょう。

S3Bucket bucket = s3Service.createBucket("mybucket");

これは例外で失敗します:

org.jets3t.service.S3ServiceException: Service Error Message.
  -- ResponseCode: 409, ResponseStatus: Conflict, XML Error Message:
  <!--?xml version="1.0" encoding="UTF-8"?-->
  <code>BucketAlreadyExists</code> The requested bucket name is not available. 
  The bucket namespace is shared by all users of the system.
  Please select a different name and try again.
  mybucket 07BE34FF3113ECCF 
at org.jets3t.service.S3Service.createBucket(S3Service.java:1586)

mybucket」という名前は、予想通り、すでに使用されています。 チュートリアルの残りの部分では、名前を作成します。

別の名前でもう一度試してみましょう。

S3Bucket bucket = s3Service.createBucket("myuniquename");
log.info(bucket);

一意の名前で呼び出しが成功し、バケットに関する情報が表示されます。

[INFO] JetS3tClient - S3Bucket
[name=myuniquename,location=US,creationDate=Sat Mar 31 16:47:47 EDT 2018,owner=null]

4.2. バケットの削除

バケットの削除は、1つを除いて、作成するのと同じくらい簡単です。 バケットを取り外す前に、バケットを空にする必要があります!

s3Service.deleteBucket("myuniquename");

これにより、空ではないバケットの例外がスローされます。

4.3. バケット領域の指定

バケットは特定のデータセンターで作成できます。JetS3tの場合、デフォルトは米国のバージニア州北部、つまり「us-east-1」です。

別のリージョンを指定することで、これをオーバーライドできます。

S3Bucket euBucket 
  = s3Service.createBucket("eu-bucket", S3Bucket.LOCATION_EUROPE);
S3Bucket usWestBucket = s3Service
  .createBucket("us-west-bucket", S3Bucket.LOCATION_US_WEST);
S3Bucket asiaPacificBucket = s3Service
  .createBucket("asia-pacific-bucket", S3Bucket.LOCATION_ASIA_PACIFIC);

JetS3tには、定数として定義されたリージョンの広範なリストがあります。

5. データのアップロード、ダウンロード、および削除

バケットができたら、それにオブジェクトを追加できます。 バケットは長持ちすることを目的としており、バケットに含めることができるオブジェクトのサイズや数に厳しい制限はありません。

S3Objectsを作成してデータをS3にアップロードします。InputStreamからデータをアップロードできますが、JetS3tはStringsand Filesの便利なメソッドも提供します。

5.1. 文字列データ

最初にStringsを見てみましょう。

S3Object stringObject = new S3Object("object name", "string object");
s3Service.putObject("myuniquebucket", stringObject);

バケットと同様に、オブジェクトには名前がありますが、ただし、オブジェクト名はバケット内にのみ存在するため、グローバルに一意であることを心配する必要はありません。

名前とデータをコンストラクターに渡すことでオブジェクトを作成します。 次に、putObject。を使用して保存します

このメソッドを使用してStringsをJetS3tで保存すると、正しいコンテンツタイプが設定されます。

オブジェクトに関する情報をS3に照会し、コンテンツタイプを見てみましょう。

StorageObject objectDetailsOnly 
  = s3Service.getObjectDetails("myuniquebucket", "my string");
log.info("Content type: " + objectDetailsOnly.getContentType() + " length: " 
  + objectDetailsOnly.getContentLength());

ObjectDetailsOnly()は、オブジェクトのメタデータをダウンロードせずに取得します。 コンテンツタイプをログに記録すると、次のように表示されます。

[INFO] JetS3tClient - Content type: text/plain; charset=utf-8 length: 9

JetS3tはデータをテキストとして識別し、長さを設定しました。

データをダウンロードして、アップロードしたものと比較してみましょう。

S3Object downloadObject = 
  s3Service.getObject("myuniquebucket, "string object");
String downloadString = new BufferedReader(new InputStreamReader(
  object.getDataInputStream())).lines().collect(Collectors.joining("\n"));
 
assertTrue("string object".equals(downloadString));

データは、アップロードに使用したのと同じ S3Object で取得され、バイトはDataInputStreamで使用可能です。

5.2. ファイルデータ

ファイルをアップロードするプロセスは、Stringsに似ています。

File file = new File("src/test/resources/test.jpg");
S3Object fileObject = new S3Object(file);
s3Service.putObject("myuniquebucket", fileObject);

S3Objects ファイルが渡されると、それらに含まれるファイルのベース名から名前が取得されます。

[INFO] JetS3tClient - File object name is test.jpg

JetS3tはファイルを取得し、アップロードします。クラスパスから mime.typesファイルをロードし、それを使用してファイルのタイプと送信されたコンテンツタイプを適切に識別しようとします。

ファイルアップロードのオブジェクト情報を取得して、次のコンテンツタイプを取得すると、次のようになります。

[INFO] JetS3tClient - Content type:application/octet-stream

ファイルを新しいファイルにダウンロードして、内容を比較してみましょう。

String getFileMD5(String filename) throws IOException {
    try (FileInputStream fis = new FileInputStream(new File(filename))) {
        return DigestUtils.md5Hex(fis);
    }
}

S3Object fileObject = s3Service.getObject("myuniquebucket", "test.jpg"); 
File newFile = new File("/tmp/newtest.jpg"); 
Files.copy(fileObject.getDataInputStream(), newFile.toPath(), 
  StandardCopyOption.REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/newtest.jpg");
assertTrue(origMD5.equals(newMD5));

Strings と同様に、オブジェクトをダウンロードし、DataInputStreamを使用して新しいファイルを作成しました。 次に、両方のファイルのMD5ハッシュを計算し、それらを比較しました。

5.3. ストリーミングデータ

StringsまたはFiles以外のオブジェクトをアップロードする場合、やるべきことがもう少しあります。

ArrayList<Integer> numbers = new ArrayList<>();
// adding elements to the ArrayList

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytes);
objectOutputStream.writeObject(numbers);

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes.toByteArray());

S3Object streamObject = new S3Object("stream");
streamObject.setDataInputStream(byteArrayInputStream);
streamObject.setContentLength(byteArrayInputStream.available());
streamObject.setContentType("binary/octet-stream");

s3Service.putObject(BucketName, streamObject);

アップロードする前に、コンテンツの種類と長さを設定する必要があります。

このストリームを取得することは、プロセスを逆にすることを意味します。

S3Object newStreamObject = s3Service.getObject(BucketName, "stream");

ObjectInputStream objectInputStream = new ObjectInputStream(
  newStreamObject.getDataInputStream());
ArrayList<Integer> newNumbers = (ArrayList<Integer>) objectInputStream
  .readObject();

assertEquals(2, (int) newNumbers.get(0));
assertEquals(3, (int) newNumbers.get(1));
assertEquals(5, (int) newNumbers.get(2));
assertEquals(7, (int) newNumbers.get(3));

さまざまなデータ型の場合、コンテンツタイププロパティを使用して、オブジェクトをデコードするためのさまざまな方法を選択できます。

6. データのコピー、移動、名前の変更

6.1. オブジェクトのコピー

オブジェクトは、取得せずにS3内にコピーできます。

セクション5.2からテストファイルをコピーして、結果を確認しましょう。

S3Object targetObject = new S3Object("testcopy.jpg");
s3Service.copyObject(
  BucketName, "test.jpg", 
  "myuniquebucket", targetObject, false);
S3Object newFileObject = s3Service.getObject(
  "myuniquebucket", "testcopy.jpg");

File newFile = new File("src/test/resources/testcopy.jpg");
Files.copy(
  newFileObject.getDataInputStream(), 
  newFile.toPath(), 
  REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/testcopy.jpg");
 
assertTrue(origMD5.equals(newMD5));

同じバケット内、または2つの異なるバケット間でオブジェクトをコピーできます。

最後の引数がtrueの場合、コピーされたオブジェクトは新しいメタデータを受け取ります。 それ以外の場合は、ソースオブジェクトのメタデータを保持します。

メタデータを変更する場合は、フラグをtrueに設定できます。

targetObject = new S3Object("testcopy.jpg");
targetObject.addMetadata("My_Custom_Field", "Hello, World!");
s3Service.copyObject(
  "myuniquebucket", "test.jpg", 
  "myuniquebucket", targetObject, true);

6.2. オブジェクトの移動

オブジェクトは同じリージョン内の別のS3バケットに移動できます。移動操作はコピーと削除の操作です。

コピー操作が失敗した場合、ソースオブジェクトは削除されません。 削除操作が失敗した場合でも、オブジェクトはソースと宛先の場所に存在します。

オブジェクトの移動は、コピーと似ています。

s3Service.moveObject(
  "myuniquebucket",
  "test.jpg",
  "myotheruniquebucket",
  new S3Object("spidey.jpg"),
  false);

6.3. オブジェクトの名前を変更する

JetS3tには、オブジェクトの名前を変更するための便利なメソッドがあります。オブジェクト名を変更するには、新しいS3Objectで呼び出すだけです。

s3Service.renameObject(
  "myuniquebucket", "test.jpg", new S3Object("spidey.jpg"));

7. 結論

このチュートリアルでは、JetS3tを使用してAmazonS3に接続しました。 バケットを作成および削除しました。 次に、さまざまなタイプのデータをバケットに追加し、データを取得しました。 最後に、データをコピーして移動しました。

コードサンプルは、いつものように、GitHubにあります。