2020.11.17

パッケージ開発をしよう! 保護されたカスタムメタデータの活用

  • このエントリーをはてなブックマークに追加
  • follow us in feedly
gettyimages (17768)

みなさん、はじめまして。
テラスカイの鈴木です。

普段はOMLINE-I、OMLINE-OといったAppExchangeパッケージの開発を行っています。
今回はそんなパッケージ開発で活用される「保護されたカスタムメタデータ」とその利用方法についてご紹介したいと思います。

保護されたカスタムメタデータとは?

保護されたカスタムメタデータは管理パッケージで利用するサーバURLなどの機密情報を保持しておく場所として利用されます。
そのため、保護されたカスタムメタデータは管理パッケージでのみ作成可能で、通常のカスタムメタデータと違い、 インストール先の組織では参照できません。
一般的なカスタムメタデータは作成した組織内で自由に参照・編集・レコード管理が可能ですが、保護されたカスタムメタデータは基本的に管理パッケージ内のApexコードのみ参照・編集・レコード管理が可能です。

カスタムメタデータの種類 アクセシビリティ
カスタムメタデータ 作成した組織内で参照・編集・レコード管理が可能。
保護されたカスタムメタデータ インストール先の組織では参照・編集・レコード管理不可。同じ管理パッケージ内のApexコードのみが参照・編集・レコード管理可能。
その他に、各API利用時の挙動などに変化があるため利用する場合は注意しましょう。
https://help.salesforce.com/articleView?id=custommetadatatypes_package_access.htm&type=5

保護されたカスタムメタデータの利用

保護されたカスタムメタデータは、インストール先組織でレコード管理ができません。
しかし、外部サービスのアクセストークンのような組織ごとに値が違う機密情報を保持したい場合など、インストール先組織から保護されたカスタムメタデータのレコードを編集したいユースケースは存在します。

OMLINE-Iではこの問題を解決するために、管理パッケージに保護されたカスタムメタデータにアクセスするためのApexクラスを用意しています。
保護されたカスタムメタデータにアクセスするためのApexクラスを提供することで、インストール先組織から参照・編集できるようになり、組織ごとの設定や拡張が可能になるわけです。

それでは、具体的な方法を確認していきましょう。

1.保護されたカスタムメタデータの作成

まずは、保護されたカスタムメタデータを作成してみましょう。
今回は比較のために、公開された通常のカスタムメタデータも一緒に作成します。

2.アクセス用のApexクラスの作成

次に、保護されたカスタムメタデータを扱うApexクラスを作成します。
OMLINE-Iでは保護されたカスタムメタデータのモデルクラスと、レコードを扱う処理をまとめたサービスクラスをglobalで提供しています。
こうすることで保護されたカスタムメタデータへのアクセスが可能となり、参照させたくない項目の制御も可能になります。

global class ProtectedCustomMetadata {
    global String label = null;
    global String developerName = null;
    global String protectedField = null;

    global ProtectedCustomMetadata() {
    }
    global ProtectedCustomMetadata(String label, String name, String text) {
        this.label = label;
        this.developerName = name;
        this.protectedField = text;
    }
    global ProtectedCustomMetadata(ProtectedCustomMetadata__mdt record) {
        this.label = record.label;
        this.developerName = record.DeveloperName;
        this.protectedField = record.ProtectedField__c;
    }
}
モデルクラス
global with sharing class CustomMetadataService {
    /* 
     * developerNameを指定してレコードを取得するメソッド
     * 戻り値はパッケージ内でglobalに宣言したラッパークラス
     */
    global ProtectedCustomMetadata get(String developerName) {
        ProtectedCustomMetadata__mdt[] records = [
            select Id
                 , label
                 , DeveloperName
                 , ProtectedField__c
              from ProtectedCustomMetadata__mdt
             where DeveloperName = :developerName
        ];
        if (records.size() == 0) {
            return null;
        }
        return new ProtectedCustomMetadata(records[0]);
    }

    /* 
     * 全レコードを取得するメソッド
     * 戻り値はパッケージ内でglobalに宣言したラッパークラスの配列
     */
    global ProtectedCustomMetadata[] getAll() {
        ProtectedCustomMetadata__mdt[] records = [
            select Id
                 , label
                 , DeveloperName
                 , ProtectedField__c
              from ProtectedCustomMetadata__mdt
        ];
        ProtectedCustomMetadata[] metadataList = new ProtectedCustomMetadata[0];
        for (ProtectedCustomMetadata__mdt record : records) {
            metadataList.add(new ProtectedCustomMetadata(record));
        }
        return metadataList;
    }
    
    /* 
     * パッケージ内でglobalに宣言したラッパークラスを受け取り
     * 保護されたカスタムメタデータのレコードを作成するメソッド
     * 
     * 実際にデプロイする処理はテストクラスでテストできないため、別メソッドとして分離する。
     */
    global Id deploy(ProtectedCustomMetadata customMeta) {
        Metadata.DeployContainer container = createDeployContainer(customMeta);
        return Metadata.Operations.enqueueDeployment(container , null);
    }
    
    /* 
     * パッケージ内でglobalに宣言したラッパークラスを受け取り
     * 保護されたカスタムメタデータのレコードを作成するメソッド
     * 
     * デプロイ処理はテストクラスで実行できないため、デプロイするメタデータの作成処理を別メソッドとして分離する。
     * テストクラスでは本メソッドの戻り値から含まれるメタデータを取得して比較する。
     * 例)
     * Metadata.DeployContainer container = service.createDeployContainer(customMeta);
     * Metadata.Metadata[] contents = container.getMetadata();
     * System.assertEquals(1, contents.size());
     */
    @TestVisible
    private Metadata.DeployContainer createDeployContainer(ProtectedCustomMetadata customMeta) {
        Metadata.CustomMetadata customMetadata = new Metadata.CustomMetadata();
        customMetadata.fullName = 'SuzukiExample__ProtectedCustomMetadata__mdt.' + customMeta.DeveloperName;
        customMetadata.label = customMeta.label;

        Metadata.CustomMetadataValue field = new Metadata.CustomMetadataValue();
        field.field = 'SuzukiExample__ProtectedField__c';
        field.value = customMeta.protectedField;
        customMetadata.values.add(field);

        Metadata.DeployContainer container = new Metadata.DeployContainer();
        container.addMetadata(customMetadata);
        return container;
    }
}
サービスクラス

3.管理パッケージの作成

それではいよいよ、管理パッケージを作成してみます。
管理パッケージ内には、各カスタムメタデータとApexクラスを追加しましょう。

4.パッケージのインストール

管理パッケージの作成が終わった後は、実際にインストールして、保護されたカスタムメタデータを利用してみましょう。

5.Apexクラスのメタデータリリース許可

Apexクラスからメタデータのデプロイを行う場合、「Apex設定」からメタデータのリリースを許可する必要があります。

6.カスタムメタデータとの比較

まずは標準画面からカスタムメタデータを確認してみます。

画像のように、公開カスタムメタデータのみ表示され、保護されたカスタムメタデータは表示されません。
インストール先組織では保護されたカスタムメタデータが参照できなくなっています。

次にSOQLを実行し、Apexからもカスタムメタデータが参照できないことを確認しましょう。
下記のようなApexを匿名実行してみます。

System.debug([
    select Id 
      from SuzukiExample__ProtectedCustomMetadata__mdt
]);
保護されたカスタムメタデータの取得

下記のようなエラーが発生し、Apexからも参照できないことが確認できます。

今度は管理パッケージ内のサービスクラスを用いて、デプロイとレコード取得をしてみましょう。
下記のApexコードを匿名実行してみます。

SuzukiExample.ProtectedCustomMetadata customMeta
    = new SuzukiExample.ProtectedCustomMetadata('TestCustomMeta', 'TestCustomMeta', 'TestField');
SuzukiExample.CustomMetadataService service = new SuzukiExample.CustomMetadataService();
service.deploy(customMeta);
保護されたカスタムメタデータのデプロイ

その後、「リリース状況」からメタデータのデプロイが完了したことを確認し、下記のApexコードを匿名実行します。

SuzukiExample.CustomMetadataService service = new SuzukiExample.CustomMetadataService();
System.debug(service.getAll());
保護されたカスタムメタデータのレコード取得

管理パッケージから提供されたApexクラスでレコードの取得ができました!

このように同じ管理パッケージ内のApexコードを用いて、インストール先組織で実装したApexコードから保護されたカスタムメタデータを参照したり、専用のVisualforce画面を開発して、一部の項目のみユーザに入力してもらったりすることができます。

テストクラスについて

保護されたメタデータのデプロイ処理を提供する場合、テストクラスの作成に注意が必要です。 テストクラスでは実際にメタデータのデプロイすることはできません。 そのため、テストクラスでは

  • デプロイ予定のコンポーネントのチェック
  • デプロイ後のコールバックのテスト

保護されたカスタム設定の利用

今回は、セキュアなデータの保管場所として保護されたカスタムメタデータをご紹介しました。
しかし、一方で カスタム設定 もパッケージの機密情報を保持する目的で利用できます。

カスタムメタデータと同じように、カスタム設定も保護することが可能です。
両者の使い分けポイントとしては、下記が挙げられます。

カスタム設定 組織レベル、プロファイルごと、ユーザごとの設定が可能。
カスタムメタデータ レコード単位で設定の管理が可能。

最後に

いかがだったでしょうか。 保護されたカスタムメタデータはセキュアな分、扱いの難しい機能でもあります。
しかし、パッケージを提供するうえで大切な機能の一つですので、ぜひ利用してみてください!

46 件
     
  • banner
  • banner

関連する記事