みなさん、はじめまして。
テラスカイの鈴木です。
普段はOMLINE-I、OMLINE-OといったAppExchangeパッケージの開発を行っています。
今回はそんなパッケージ開発で活用される「保護されたカスタムメタデータ」とその利用方法についてご紹介したいと思います。
保護されたカスタムメタデータとは?
保護されたカスタムメタデータは管理パッケージで利用するサーバURLなどの機密情報を保持しておく場所として利用されます。
そのため、保護されたカスタムメタデータは管理パッケージでのみ作成可能で、通常のカスタムメタデータと違い、 インストール先の組織では参照できません。
一般的なカスタムメタデータは作成した組織内で自由に参照・編集・レコード管理が可能ですが、保護されたカスタムメタデータは基本的に管理パッケージ内のApexコードのみ参照・編集・レコード管理が可能です。
カスタムメタデータの種類 | アクセシビリティ |
---|---|
カスタムメタデータ | 作成した組織内で参照・編集・レコード管理が可能。 |
保護されたカスタムメタデータ | インストール先の組織では参照・編集・レコード管理不可。同じ管理パッケージ内のApexコードのみが参照・編集・レコード管理可能。 |
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画面を開発して、一部の項目のみユーザに入力してもらったりすることができます。
テストクラスについて
保護されたメタデータのデプロイ処理を提供する場合、テストクラスの作成に注意が必要です。 テストクラスでは実際にメタデータのデプロイすることはできません。 そのため、テストクラスでは
- デプロイ予定のコンポーネントのチェック
- デプロイ後のコールバックのテスト
保護されたカスタム設定の利用
今回は、セキュアなデータの保管場所として保護されたカスタムメタデータをご紹介しました。
しかし、一方で カスタム設定 もパッケージの機密情報を保持する目的で利用できます。
カスタムメタデータと同じように、カスタム設定も保護することが可能です。
両者の使い分けポイントとしては、下記が挙げられます。
カスタム設定 | 組織レベル、プロファイルごと、ユーザごとの設定が可能。 |
カスタムメタデータ | レコード単位で設定の管理が可能。 |
最後に
いかがだったでしょうか。
保護されたカスタムメタデータはセキュアな分、扱いの難しい機能でもあります。
しかし、パッケージを提供するうえで大切な機能の一つですので、ぜひ利用してみてください!
https://help.salesforce.com/articleView?id=custommetadatatypes_limitations.htm&type=5
https://help.salesforce.com/articleView?id=custommetadatatypes_protection.htm&type=5
https://help.salesforce.com/articleView?id=custommetadatatypes_package_access.htm&type=5
https://help.salesforce.com/articleView?id=custommetadatatypes_relationships_limits.htm&type=5