新しい Dockerベースの Cosmos Emulator を Java から使ってみる

# 新しい Cosmos Emulator を Java から使ってみる

新しい Cosmos Emulator がリリースされました。このエミュレータは、Linux ベースのエミュレータは Docker イメージとして提供されてます。

[Linux ベースのエミュレータ (プレビュー) - Azure Cosmos DB for NoSQL | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/cosmos-db/emulator-linux)

現時点でプレビューなのですが、提供されている機能がいままでのエミュレータに比べて少なく、現時点ではすべての機能が使えるわけではありません。

## 起動方法

Java から使う場合は、 `https` が必須なので、デフォルトで起動する `http` ではなく、 `https` で起動する必要があります。`--protocol https` オプションを指定しましょう。

```shell
docker run --detach --publish 8081:8081 --publish 1234:1234 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview --protocol https
```

起動後、 http://localhost:1234/ にアクセスしていつもの Cosmos Explorer 画面が表示されれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34017/5672e2f9-51ca-28d1-c42e-c8e1b95f8fa6.png)


docker compose で起動したい場合は、以下のように `docker-compose.yml` を作成しましょう。データを永続化したい場合は、`data` をローカルにマウントしておけばOKそうです。

```yaml
version: '3.8'
services:
  cosmos:
    image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview
    ports:
      - "8081:8081"
      - "1234:1234"
    environment:
      - PROTOCOL=https
    volumes:
      - ./cosmos-data:/data
```

## 証明書の登録

Java の面倒なところは、証明書を登録しないと SDK が動かないところです。以下のコマンドで証明書を登録しましょう。

`openssl` と `sed` を使う必要があるって面倒なですが、`sed` は特定の文字列を抽出するために使っているだけなので、最悪 `openssl` の出力を手動で切った張ったすれば問題ないです。

```shell
openssl s_client -connect localhost:8081 </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cosmos.cert
```

以下が抜き出した物ですが、今のところ不変のようです。コンテナ削除しても同じです。以前のエミュータは毎度生成されなおして難儀した覚えがあります。

```
-----BEGIN CERTIFICATE-----
MIIFCTCCAvGgAwIBAgIUAUMCOUUjCpZdDek8wMd51nhBezkwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDEyODA3MTgwNFoXDTM1MDEy
NjA3MTgwNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEAmH5YJP1fnv1P2EDq5xAQisyWZjfSICA/7sGvaM53T5Ee
YAJ2irYRWVGy6YB8OTUMcFnCKZzr/br5CB64giU/oZb4XCJcNPf6CUR99xYD9dEC
S8lQuy415tp7fn4uf4T5+DHYlXTrnN+m0C7qJ3B4l9OGaTQds4MrA62Sq0/FAZxA
mRSQ00y8rKVLDcRRyFoVpJTK8HIYHcXdP4OainBvrJc1ozFz0Jvq+rqKAsLPXmIK
JIu/34ms6RxHPPvwmz9egrpsqD9RNaVEUVHfBqg2jxsGH2ir4VccEwexYDp9AgKC
fk4yqe/A5XfCLS9C2OKV84+y6FMIt3a86c/UmVwChJippEpOCvn58zzHoswIKJ8S
t+uWeISTBXWRmTgMsInXNhJ7Zc7Z/gWsm1rhfWXdNH0FVPN0wJzWrxwqX9pfDgcr
402X4Seh7s8VBAc0LiVgGmTjtfpoO2J3jdqWX7ahkXMKI/TyWLJ1wE7NR/JzeWN6
AFQnodVTYRznOEeKuiX1b9hRm7PQ4kNKdOkncM91DsCfgyccpS+ci7VVejUwg2Tm
XrMwEUl7ftCzOUz4S9M8JrXlue2BzPLsQCsRpNLqR274ApbC9ye+tbig535tQBvo
JOWBXsY61msDkQL+k3DI6h84CoNN0AP0AtW1Gq3E+6h96q+RzU8M56WydPvUGLsC
AwEAAaNTMFEwHQYDVR0OBBYEFGBG+CdD4YurEzLlDC7koIEhM3qaMB8GA1UdIwQY
MBaAFGBG+CdD4YurEzLlDC7koIEhM3qaMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggIBAHGS7slctG3lGzA3r/v53a2F+d/R60ttfTVIywwfiIhmhbJE
5BwldBfBHa5bCj3w7VoXIN8rRuDN6XNGLAML4pBfHMKz9lHc7zT2c4zNQMGIgNUK
fjZmdhrAZFySuclc2cjHnBinEhIeCaSBZkOSlQ/AtirHi73ML1u/4X5QsJJbLkJ7
CUVQKJDqLF3WQKnxcAIDTXqB6puahwzYJKXTOYUlw3aqqeduwmtkANdk9P0WtxFJ
6bBJ4ANzrsZci5zbUy5e0FjMFswS62RBlK782vBRQxAsckGLqG9118RnsugDexAB
LyPy5ulbGpq5Il0c5w32vC+qCa6mQjK7PB+VTEWHaZLsiuh/MQHI3AmDGiMls+vj
zvjDIVaW/vNPKt7NzZ2sCqFWcVl6ERMjO+B3f+FVwSA2r3B89oHbtyuFpGir2Nyy
aaDhXdLexB9Z/BMGfCaBcP0WqAYbsc5ewwCD/Ekb8RyK+KxiddZkWc2fDeFZPbaS
fufefuQ4kZRCDHx9SxoP28aSMY1GxMVasVTj5guiYteFveDZ5EEziKLO8qky/jXZ
zqnlNSVUocwnTB7vH/ZBjrv16LVj1f9rHPtptypuT55cNUoEFf2vEh0dATBJsFjV
9svVSl6oY/nHFS3zSkgAQr/bmCvCyte4ZPQZqBCgrWhT7kIZ4DLi0iEAsVfA
-----END CERTIFICATE-----
```

`keytool` で証明書を登録しましょう。キーストアのパスワードは、だいたいデフォルトの `changeit` になっているでしょう。場合によっては管理者権限が必要かもしれません。

```shell
keytool -cacerts -importcert -alias cosmos_emulator -file cosmos.cert
```

因みに削除は以下。

```shell
keytool -cacerts -delete -alias cosmos_emulator
```

## Java から使う

`pom.xml` に SDK の依存を追加しましょう。BOM使うとバージョンが揃って便利です。

```xml

<dependencies>
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-cosmos</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
<dependencies>
    <!-- https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/boms/azure-sdk-bom/README.md -->
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-sdk-bom</artifactId>
        <version>1.2.30</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencies>
</dependencyManagement>
```

ざっと以下のようなテストコードを作成して、作成と読み込みができることを確認します。DBとコンテナは手動で作っておきます。

```java

@Test
public void createAndRead() {
    CosmosClient client = new CosmosClientBuilder()
            .endpoint("https://localhost:8081/")
            .key("C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==")
            .buildClient();

    CosmosContainer container = client.getDatabase("testdb").getContainer("container");
    var item = new Person();
    item.setId("1");
    item.setName("John");
    item.setAge(30);

    // 作成
    container.createItem(item);

    // 読み込み
    var readItem = container.readItem("1", new PartitionKey("1"), Person.class);
    System.out.println(readItem.getItem());
    client.close();
}
```

実行すると、単純な作成と読み込みができませし、未実装ってなんやねん。普通にWindows版のエミュレータでは何の問題もなく動きます。

```json
{
  "innerErrorMessage": "System.NotImplementedException: Have not implemented Read on Address.  ..."
}
```

未実装にも程があるやろと、色々調べまわったのですが、結局は **ゲートウェイモード** にしてなかったというオチでした。クライアントを作成するときに `.gatewayMode()` を差し込んでおきましょう。

## まとめ

新しい docker ベース の cosmos は起動も速く使い勝ってもよさそうですが、いかんせんサポートされている機能が少なすぎる気がします。もうすこしのアップデートに期待でしょうか。

Issueなどはここを見ればわかります。

[Azure/azure-cosmos-db-emulator-docker: This repo serves as hub for managing issues, gathering feedback, and having discussions regarding the Cosmos DB Emulator Docker.](https://github.com/Azure/azure-cosmos-db-emulator-docker)