プログラマ38の日記

主にプログラムメモです。

Salesforce: メタデータダウンロードツールとExcel項目取得ツールのバージョンを上げました(ApiVer45)

Spring19のリリースに伴い次のツールのバージョンを上げました。

Spring19で、オブジェクトが増えていたりメタデータが追加されていたりします。
最低確保されるディスク容量も増えるようですし、どんどん機能が増えていくのは嬉しいですね。

 

ツールをアップするストレージはGoogleドライブを使っているのですが、メタデータダウンロードツールはそれなりにファイルが大きいので気長にダウンロードしてください。ソースファイルもつけてますので、安心して使って欲しいなと思います。

最後に

いくつかのメタデータのファイル名は物理名(API名)ではなくて、ラベル名がそのまま使用されるものがあります。代表的なものとして、プロファイル・レイアウト・ホームページレイアウトなどがあります。

ファイル名として使えない文字はメタデータファイルではURLエンコードされるのですが、「*」だけはメタデータのファイル名に含まれてしまいます。

その結果、Salesforceが提供されているツールでは、「*」が含まれるメタデータファイルは、エラーとなり保存できません。

そこで、このメタデータダウンロードツールでは「*」を「%2a」に変換することでエラーにならないようにしています。

注意点として、Ant Migration Toolなどpackage.xmlを使ってデプロイする場合、このダウンロードしたファイル名に合わせてpackage.xmlコンポーネント名を変更しておく必要があります。

名前を合わせておけばデプロイはエラーとならず、「*」のつくコンポーネントをデプロイすることができます。

メタデータのリクエスト時に、「*」を「%2a」に変換しておけば、package.xmlでは%2aに変換後のコンポーネント名で出力されます。このようにメタデータダウンロードツールは変更してます。
※「%2a」はデプロイ後は「*」に変換されます。

Salesforce: プロファイルのメタデータファイルの物理名と画面の表示名の対応

プロファイルのメタデータを使って権限を確認したり、他のプロファイルや、別の環境のプロファイルを比較をすることは多いと思います。
ですが、権限の物理名と表示名の対応させるのが難しく対応表を作成しました。

プロファイルは、様々な設定で権限が増えるので全て網羅できているわけではないですが現時点の調査した結果を表にしました。
システム管理者権限と一般権限は分けていないのですが、十分使えると考えています。

 

メタデータ物理名 画面表示名
AccessCMC コミュニティ管理にアクセス
ActivateContract 契約の有効化
ActivateOrder 注文の有効化
ActivitiesAccess アクセス活動 (ToDo と行動)
AddDirectMessageMembers ダイレクトメッセージに人を追加
AllowEmailIC メールベースの ID 検証オプション
AllowLightningLogin Lightning Login ユーザ
AllowUniversalSearch Knowledge One
AllowViewEditConvertedLeads 取引開始済みのリードを表示および編集
AllowViewKnowledge ナレッジの参照を許可
ApexRestServices Apex REST サービス
ApiEnabled API の有効化
ApiUserOnly API 限定ユーザ
ApproveContract 契約の承認
AssignPermissionSets 権限セットの割り当て
AssignTopics トピックを割り当てる
AuthorApex Apex 開発
BulkApiHardDelete Bulk API の物理削除
BulkMacrosAllowed 複数のレコードに対してマクロを実行
CampaignInfluence2 キャンペーンインフルエンス
CanApproveFeedPost フィード投稿とコメントを承認可能
CanInsertFeedSystemFields Chatter フィードにシステム項目値を挿入
CanManageMaps Analytics のカスタム地図を管理
CanUseNewDashboardBuilder ドラッグアンドドロップ ダッシュボードビルダー
CanVerifyComment Chatter の質問への回答の確認
ChangeDashboardColors ダッシュボードの色を変更
ChatterComposeUiCodesnippet UI からのコードスニペットの挿入を許可
ChatterEditOwnPost 自分の投稿を編集
ChatterEditOwnRecordPost 自分の所有レコードへの投稿を編集
ChatterFileLink 公開リンクの作成
ChatterInternalUser Chatter 内部ユーザ
ChatterInviteExternalUsers Chatter に顧客を招待する
ChatterOwnGroups 新規 Chatter グループの作成および所有
CloseConversations 会話スレッドを閉じる
ConfigCustomRecs カスタムおすすめの設定
ConnectOrgToEnvironmentHub 環境ハブに組織を接続
ContentAdministrator Salesforce CRM Content の管理
ContentWorkspaces ライブラリへのアクセス
ConvertLeads リードの取引の開始
CreateAuditFields レコードの作成時に監査項目を設定
CreateCustomizeDashboards ダッシュボードの作成とカスタマイズ
CreateCustomizeFilters リストビューを作成およびカスタマイズ
CreateCustomizeReports レポートの作成とカスタマイズ
CreateDashboardFolders ダッシュボードフォルダを作成
CreateLtngTempFolder Lightning メールテンプレートのフォルダを作成
CreateLtngTempInPub 公開 Lightning メールテンプレートを管理
CreatePackaging AppExchange パッケージの作成
CreateReportFolders レポートフォルダを作成
CreateReportInLightning レポートビルダー (Lightning Experience)
CreateTopics トピックを作成
CreateWorkBadgeDefinition カスタムバッジ定義を作成
CreateWorkspaces ライブラリの作成
CustomMobileAppsAccess カスタムモバイルアプリケーションにアクセス
CustomSidebarOnAllPages すべてのページにカスタムサイドバーを表示
CustomizeApplication アプリケーションのカスタマイズ
DataExport ウィークリーデータのエクスポート
DelegatedTwoFactor ユーザインターフェースで 2 要素認証を管理
DeleteActivatedContract 有効契約の削除
DeleteFieldHistory  「項目履歴から削除」を有効化
DeleteFieldHistoryArchive  「項目履歴アーカイブから削除」を有効化
DeleteTopics トピックを削除
DistributeFromPersWksp コンテンツ配信の作成
EditActivatedOrders 有効化された注文の編集
EditBillingInfo 請求情報の管理
EditBrandTemplates レターヘッドの管理
EditCaseComments ケースコメントの編集
EditEvent 行動の編集
EditHtmlTemplates HTML テンプレートの編集
EditKnowledge 記事の管理
EditMyDashboards 私のダッシュボードを編集
EditMyReports 私のレポートを編集
EditOppLineItemUnitPrice 商談商品の販売価格の編集
EditPublicDocuments 公開ドキュメントの管理
EditPublicFilters 公開リストビューの管理
EditPublicTemplates Classic の公開メールテンプレートを管理
EditReadonlyFields 参照のみ項目の編集
EditTask ToDo の編集
EditTopics トピックを編集
EmailMass 一括メール送信
EmailSingle メールの送信
EnableCommunityAppLauncher コミュニティでアプリケーションランチャーを表示
EnableNotifications アウトバウンドメッセージの送信
ExportReport レポートのエクスポート
FeedPinning フィードでの投稿の固定
ForceTwoFactor ユーザインターフェースログインの 2 要素認証
GiveRecognitionBadge Lightning コミュニティのレコグニションバッジの付与
GovernNetworks コミュニティを管理する
HideReadByList [表示先] リストを非表示
IPRestrictRequests IP 制限要求
IdentityEnabled Identity 機能を使用
ImportCustomObjects カスタムオブジェクトのインポート
ImportLeads リードのインポート
ImportPersonal 個人データのインポート
InboundMigrationToolsUser 変更セットのリリース
InsightsAppAdmin Analytics の管理
InsightsAppUser Analytics の使用
InstallPackaging AppExchange パッケージのダウンロード
LightningConsoleAllowedForUser Lightning コンソールユーザ
LightningExperienceUser Lightning Experience ユーザ
ListEmailSend リストメールの送信を許可
LtngPromoReserved01UserPerm Salesforce Classic にとどまる
ManageAnalyticSnapshots レポート作成スナップショットを管理
ManageAuthProviders 認証プロバイダの管理
ManageBusinessHourHolidays 営業時間の休日の管理
ManageCallCenters コールセンターの管理
ManageCases ケースの管理
ManageCategories カテゴリの管理
ManageCertificates 証明書を管理
ManageChatterMessages Chatter メッセージとダイレクトメッセージを管理
ManageContentPermissions コンテンツ権限の管理
ManageContentProperties コンテンツプロパティの管理
ManageContentTypes ファイルのレコードタイプおよびレイアウトの管理
ManageCssUsers カスタマーユーザを管理
ManageCustomPermissions カスタム権限を管理
ManageCustomReportTypes カスタムレポートタイプの管理
ManageDashbdsInPubFolders 公開フォルダのダッシュボードを管理
ManageDataCategories データカテゴリの管理
ManageDataIntegrations データインテグレーションの管理
ManageDynamicDashboards 動的ダッシュボードの管理
ManageEmailClientConfig メールクライアント設定の管理
ManageEntitlements エンタイトルメントの管理
ManageExchangeConfig Lightning Sync を管理
ManageHealthCheck 状態チェックを管理
ManageInteraction フローの管理
ManageInternalUsers 内部ユーザを管理
ManageIpAddresses IP アドレスを管理
ManageKnowledge Salesforce ナレッジの管理
ManageKnowledgeImportExport ナレッジ記事のインポート/エクスポートの管理
ManageLeads リードの管理
ManageLoginAccessPolicies ログインアクセスポリシーを管理
ManageMobile モバイル設定を管理する
ManageNetworks コミュニティを作成および設定
ManagePackageLicenses パッケージライセンスの管理
ManagePartners 外部ユーザの管理
ManagePasswordPolicies パスワードポリシーを管理
ManageProfilesPermissionsets プロファイルおよび権限セットを管理
ManagePropositions Next Best Action Recommendations を管理
ManagePvtRptsAndDashbds すべての非公開レポートおよびダッシュボードを管理
ManageQuotas 目標を管理
ManageRecommendationStrategies Next Best Action 戦略を管理
ManageRemoteAccess 接続アプリケーションを管理する
ManageReportsInPubFolders 公開フォルダのレポートを管理
ManageRoles ロールを管理
ManageSearchPromotionRules 昇格済み検索語の管理
ManageSessionPermissionSets セッション権限セットの有効化を管理
ManageSharing 共有を管理
ManageSolutions 公開ソリューションの管理
ManageSynonyms シノニムの管理
ManageTranslation 翻訳の管理
ManageTwoFactor API で 2 要素認証を管理
ManageUnlistedGroups 「リストに記載しない」グループを管理
ManageUsers ユーザの管理
MassInlineEdit リストからの一括編集
MergeTopics トピックのマージ
ModerateChatter Chatter のモデレート
ModerateNetworkFeeds コミュニティフィードモデレート
ModerateNetworkFiles コミュニティファイルモデレート
ModerateNetworkMessages コミュニティ Chatter メッセージモデレート
ModerateNetworkUsers コミュニティユーザモデレート
ModifyAllData すべてのデータの編集
ModifyDataClassification データ分類を変更
ModifyMetadata メタデータを変更 (「すべてのデータの編集」なしで有効にした場合はベータ)
NewReportBuilder レポートビルダー
OutboundMigrationToolsUser 変更セットの作成とアップロード
OverrideForecasts 売上予測の上書き
Packaging2 第二世代パッケージの作成と更新
PasswordNeverExpires パスワード無期限
PreventClassicExperience Salesforce Classic に切り替えるオプションを非表示
PrivacyDataAccess プライバシーデータへのユーザのアクセスを許可
PublishPackaging AppExchange パッケージのアップロード
QueryAllFiles すべてのファイルをクエリ
RecordVisibilityAPI RecordVisibility API を有効化
RemoveDirectMessageMembers ダイレクトメッセージから人を削除
ResetPasswords ユーザパスワードのリセットおよびユーザのロック解除
RunFlow フローを実行
RunReports レポート実行
ScheduleJob ダッシュボードのスケジュール
ScheduleReports レポートのスケジュール
SelectFilesFromSalesforce Salesforce からファイルを選択
SendAnnouncementEmails お知らせメールを送信
SendSitRequests 登録情報照会要求の送信
ShareInternalArticles 内部のナレッジ記事を外部と共有
ShowCompanyNameAsUserBadge コミュニティロールとして会社名を表示
SocialInsightsLogoAdmin 取引先からロゴを削除
SolutionImport ソリューションのインポート
SubmitMacrosAllowed ユーザが元に戻せないマクロを管理
SubscribeDashboardRolesGrps ダッシュボードの登録: グループおよびロールへの送信
SubscribeDashboardToOtherUsers ダッシュボードの登録: 受信者を追加
SubscribeReportRolesGrps レポートの登録: グループおよびロールへの送信
SubscribeReportToOtherUsers レポートを登録: 受信者を追加
SubscribeReportsRunAsUser レポートを登録: 実行ユーザを設定
SubscribeToLightningDashboards ダッシュボードへの登録
SubscribeToLightningReports レポートを登録
TagManager タグマネージャ
TransactionalEmailSend 営業以外のメールを送信
TransferAnyCase ケース所有者の移行
TransferAnyEntity 所有権の移行
TransferAnyLead リード所有者の移行
TwoFactorApi API ログインの 2 要素認証
UpdateWithInactiveOwner 無効な所有者のレコードを更新
UseTeamReassignWizards チーム再割り当てウィザードの使用
UseWebLink カスタマイズしたアクションへのアクセスを許可
ViewAllData すべてのデータの参照
ViewAllForecasts すべての売上予測の参照
ViewAllUsers すべてのユーザの参照
ViewCaseInteraction ケースフィードを使用
ViewContent ポータルのコンテンツの参照
ViewCustomerSentiment Community 360 を表示
ViewDataAssessment データ評価の参照アクセス権
ViewDataCategories [設定] でデータカテゴリを表示
ViewEncryptedData 暗号化されたデータの参照
ViewEventLogFiles イベントログファイルを参照
ViewGlobalHeader グローバルヘッダーを参照
ViewHealthCheck 状態チェックを表示
ViewHelpLink ヘルプリンクを参照
ViewMyTeamsDashboards 私のチームのダッシュボードの参照
ViewPlatformEvents ログインフォレンジックイベントを表示
ViewPublicDashboards 公開フォルダのダッシュボードを参照
ViewPublicReports 公開フォルダのレポートを参照
ViewRoles ロールおよびロール階層を表示
ViewSetup 設定・定義を参照する
WorkCalibrationUser Work.com 調整を有効化
WorkDotComUserPerm Work.com を有効化

Salesforce: Batch Apexでビッグオブジェクト(BigOBject)に設定変更履歴エントリを蓄積してみた

f:id:crmprogrammer38:20190101140331p:plain

ビッグオブジェクトの調査をしてみて、更新・削除が頻繁に行われるデータよりはログデータのような一度作成したら更新のかからないデータを保存するのに向いているようです。

 

Salesforceでそういった特性のデータは、項目変更履歴(・・・History)や、イベントログファイル(EventLogFile)、設定変更履歴エントリ(SetupAuditTrail)などがあると思います。

項目変更履歴は標準ビッグオブジェクトが用意されているみたいなのでパス、イベントログファイルは、ログファイルのCSVを分解する必要があってお試しで作るにはボリュームがあるのでパス、ということで設定変更履歴エントリで試してみました。

 

オブジェクトを作成する

次の内容で「SetupAuditTrail__b.object」ファイルを用意しdeployする。
deploy後、プロファイルでオブジェクト権限や項目レベルセキュリティを設定する。

<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
    <deploymentStatus>Deployed</deploymentStatus>
    <fields>
        <fullName>Id__c</fullName>
        <label>Salesforce ID</label>
        <length>18</length>
        <required>true</required>
        <type>Text</type>
        <unique>false</unique>
    </fields>
    <fields>
        <fullName>Action__c</fullName>
        <label>アクション</label>
        <length>150</length>
        <required>false</required>
        <type>Text</type>
        <unique>false</unique>
    </fields>
    <fields>
        <fullName>Section__c</fullName>
        <label>セクション</label>
        <length>18</length>
        <required>false</required>
        <type>Text</type>
        <unique>false</unique>
    </fields>
    <fields>
        <fullName>CreatedDate__c</fullName>
        <label>エントリ作成日</label>
        <required>false</required>
        <type>DateTime</type>
        <unique>false</unique>
    </fields>
    <fields>
        <fullName>CreatedById__c</fullName>
        <externalId>false</externalId>
        <label>エントリ作成者</label>
        <referenceTo>User</referenceTo>
        <relationshipName>B_SetupAuditTrails</relationshipName>
        <required>false</required>
        <type>Lookup</type>
    </fields>
    <fields>
        <fullName>Display__c</fullName>
        <label>表示</label>
        <visibleLines>3</visibleLines>
        <length>1000</length>
        <required>false</required>
        <type>LongTextArea</type>
    </fields>
    <fields>
        <fullName>DelegateUser__c</fullName>
        <label>代理ユーザ</label>
        <length>80</length>
        <required>false</required>
        <type>Text</type>
    </fields>
    <fields>
        <fullName>ResponsibleNamespacePrefix__c</fullName>
        <label>ソースの名前空間プレフィックス</label>
        <length>15</length>
        <required>false</required>
        <type>Text</type>
    </fields>
    <indexes>
        <fullName>B_SetupAuditTrailIndex</fullName>
        <label>設定変更履歴エントリインデックス</label>
        <fields>
            <name>Id__c</name>
            <sortDirection>ASC</sortDirection>
        </fields>
    </indexes>
    <label>(BigObject)設定変更履歴エントリ</label>
</CustomObject>

バッチApexを作成する

次の内容で「Batch_StoreSetupAuditTrail」クラスを作成しスケジュール設定する。

global class Batch_StoreSetupAuditTrail implements Database.Batchable<Sobject> , Schedulable {

    global void execute(SchedulableContext ctx){
        Database.executebatch(new Batch_StoreSetupAuditTrail(), 200);
    }


    // The batch job starts
    global Database.Querylocator    start(Database.BatchableContext bc){
        return Database.getQuerylocator(    
            [Select
                 Id
                ,Action
                ,Section
                ,CreatedDate
                ,CreatedById
                ,Display
                ,DelegateUser
                ,ResponsibleNamespacePrefix
            From
                 SetupAuditTrail
            where CreatedDate = LAST_MONTH]
        );
    }
  
    // The batch job executes and operates on one batch of records
    global void execute(Database.BatchableContext bc, List<Sobject> scope){
  
        if(scope == null || scope.isEmpty() ){
            return;
        }
        
        List<SetupAuditTrail__b> b_rows = new List<SetupAuditTrail__b>();
        for(Sobject row : scope){
            SetupAuditTrail audit = (SetupAuditTrail)row;
            
            SetupAuditTrail__b b_row = new SetupAuditTrail__b();
            b_row.Id__c                          =audit.Id;
            b_row.Action__c                      =audit.Action;
            b_row.Section__c                     =audit.Section;
            b_row.CreatedDate__c                 =audit.CreatedDate;
            b_row.CreatedById__c                 =audit.CreatedById;
            b_row.Display__c                     =audit.Display;
            b_row.DelegateUser__c                =audit.DelegateUser;
            b_row.ResponsibleNamespacePrefix__c  =audit.ResponsibleNamespacePrefix;
            
            b_rows.add(b_row);
        }

        Database.insertImmediate(b_rows);
    }

    // The batch job finishes
    global void finish(Database.BatchableContext bc){
    }
} 

最後に

設定変更履歴エントリは、いつ、だれがどこを変更したかが追跡できて便利ですが、半年より前の履歴は消えてしまいます。そこまで追跡する必要はないかもしれないですが、履歴が残っていれば何かの時の保険として使えます。大人数で長期間で開発する場合、リリース前の最終チェックなどで使ってもいいかもしれません。

Salesforce: ビッグオブジェクト(BigObject)について調べたこと

f:id:crmprogrammer38:20181231211901p:plain
ビッグオブジェクト(BigObject)は、カスタムオブジェクトのデータ制限とは別にデータを登録ができるため、便利に利用したいなと思いました。

利用するにあたっていくつか調べたので、その結果をまとめました。調べたのは2018年12月になります。

 

 

オブジェクトの作成・更新・削除

作成
  • Spring19から画面から作成できるようになりました。そして、「[Metadata API] deployでも作成可能(一般的なツールでは、Force.com IDE、Ant Migration Tool、Salesforce Extensions For VS Code など)
  • オブジェクトのAPI名の末尾は__bとなる。
  • 作成できる項目のタイプは、テキスト/数値/日付時刻/ロングテキストエリア/参照関係項目と制限されている。(日付型はありません。)
  • BigObjectのみIndexの指定が必要(インデックスという名前ですが、プライマリキーとしての意味を持っています。)
  • インデックスに指定できるテキスト項目の桁数は最大50
  • インデックスに指定できる項目数は最大5

※[Metadata API] createMetadataではエラーが発生し解決できませんでした。

更新 画面からオブジェクトのラベル、API名が変更可能
削除  画面からオブジェクトを削除可能

項目の作成・更新・削除

作成 [Metadata API] deploy、[Metadata API] createMetadataで作成可能 
更新

画面からラベル、API名、必須項目の変更が可能

桁数の変更は不可
※画面からも、[Metadata API] deploy/updateMetadataからも桁の変更はサポートされていません。

削除 不可能
※画面上からも削除できず、[Metadata API] deleteMetadataもサポートされていません。

データの取得・作成・更新・削除

取得 [SOAP API] query、[Apex] query で取得できます。 ※queryだと、集計関数が使えませんでした。追加ライセンスで非同期SOQLが使えて、非同期SOQLは集計も可能のようです。非同期SOQLはrest apiで提供されるようです。
作成

[SOAP API] insert、[Apex] Database.insertImmediate/Database.insertAsync で登録可能 ([SOAP API]の一般的なツールでは、DataLoaderや他のサードパーティ製のツール)

オブジェクト作成時に指定したインデックスフィールドでデータが登録されてなければ追加、あれば更新のupsertの動きとなります。

※[SOAP API] insert時に、Number型の項目はBulk APIにしないとエラーが発生しました。

更新 上記、作成と同様の操作(インデックスに指定したフィールドの値がすでにあれば更新となります)
通常のオブジェクトのようにSalesforce IDでの更新ではないため、DataLoaderでUpdateではオブジェクトが表示されません。
削除 [SOAP API] deleteByExample、[Apex] Database.deleteImmedeiate/Database.deleteAsync で削除可能 ([SOAP API] deleteByExampleを実装しているツールは見当たらないため、個別に開発が必要と思われます)

その他

  • 参照先が削除された場合は、参照関係項目はnullになる。
  • 検索条件に指定する項目はインデックスで指定した項目に限定される(なので、検索で使いたい項目はインデックスに含める必要がありますが、データの更新でもインデックスは使うので設計が難しいです)
  • [SOAP API ]queryや、[Apex] queryでは、group byは使えないですが、select count() from ビッグオブジェクト は使えました。

最後に

メタデータのdeployでないと、オブジェクト自体が作成できなかったり、 Bulk APIでないと数値型がエラーになったりするなど、ハードルの高さを感じました。(そもそもBigObjectという名前なのに、検索条件項目や、集計関数に制限があり扱いが難しいです)

そして、BigObjectでのインデックスの指定がとても難しさを感じました。

インデックスはデータの更新のキーの指定でもあり、検索可能項目の指定でもあるので、どちらの用途で使うかを決めておく必要があります。

検索可能項目として指定する方がデータの取得時に便利ですが、プライマリーキーの意味を持たせ辛いためその際にはデータの更新は、特定の条件でデータを削除後、再作成とする設計にするのがいいのかなと考えました。

 

色々利用するには前提をクリアする必要がありますが、100万行の入るストレージが使えるというのはとても魅力的だなと思います。

Salesforce: java用WSC(ver44)を使ってRest APIを利用する

HttpURLConnectionを用意すればHttpヘッダやエンドポイントを指定すれば利用できますが、WSCに用意されている仕組みでRest APIを利用できます。

 

 

サンプルコード

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;

import org.codehaus.jackson.map.ObjectMapper;

import com.sforce.soap.partner.LoginResult;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectorConfig;
import com.sforce.ws.transport.JdkHttpTransport;

public class RestSample {

	public static void main(String[] args) throws Exception{
		
		//接続用情報
		String partnerEndpoint = "https://login.salesforce.com/services/Soap/u/44.0";
		String username = "sampleuser@sample.user";
		String password = "samplepassword";
		
		ConnectorConfig pConfig = new ConnectorConfig();
		pConfig.setServiceEndpoint(partnerEndpoint);
		pConfig.setManualLogin(true);		
		PartnerConnection pCon = new PartnerConnection(pConfig);
		
		//ログイン
		LoginResult lr = pCon.login(username, password);
		
		String serverUrl = lr.getServerUrl();
		String sessionId = lr.getSessionId();
		
		String url = serverUrl.substring(0, serverUrl.indexOf("/services"));
		url = url + "/services/data";
		
		HashMap<String, String> httpHeaders = new HashMap<String, String>();
		httpHeaders.put("Accept-Charset", "UTF-8");
		httpHeaders.put("Content-Type", "application/json");
		httpHeaders.put("Authorization", "Bearer " + sessionId);	
		httpHeaders.put("Accept", "application/json");
		
		//Rest用のコネクションを作成
		HttpURLConnection resthttp = JdkHttpTransport.createConnection(
		                              pConfig, new URL(url), httpHeaders, true);
		resthttp.setRequestMethod("GET");
		resthttp.setInstanceFollowRedirects(true);
		
		BufferedReader br = new BufferedReader(new InputStreamReader(
				new GZIPInputStream(resthttp.getInputStream()),"utf8"));
		
		StringWriter writer = new StringWriter();
		while(true) {
			String line = br.readLine();
			if(line == null) {
				break;
			}
			writer.append(line);
		}
		
		//返却されたJson文字列
		String jsonStr = writer.toString();
		
		//Jsonのパース
		ObjectMapper mapper = new ObjectMapper();
		Object o = mapper.readValue(jsonStr,Object.class);	
	}
}

用意されている関数

サンプルコードの青文字の太字箇所で、JdkHttpTransport.createConnection を使うことでWSCが少し便利にしてくれたHttpURLConnection を利用することができます。

便利になるのが、ConnectorConfigでhttpプロキシを指定していた場合は、JdkHttpTransport.createConnectionで作成したHttpURLConnection はそのままConnectorConfigのhttpプロキシを使用した通信となります。
※HttpURLConnectionをopenする際に別途httpプロキシを指定しなくても良くなります。

そして、JdkHttpTransport.createConnectionの、最後の引数に true を指定することでgzip圧縮した通信設定をしてくれます。(これもhttpヘッダで自分で指定すればいいだけですが・・)

とはいえ、多少なりともコードは少なります。

最後に

WSCも以前のバージョンでは、PartnerConnectionやMetadataConnectionのように、RestConnectionがあったのですが、いつの間にかなくなっていました。

そして、以前のバージョンではJson用ライブラリがGsonだったのですが、いつの間にかJacksonに変更されています。

WSCで利用するバージョンによって中身が違うので気を付けないといけないなーと思いました。

Salesforce: メタデータエクスポートツールのバージョンを上げました(APIVer44)

Salesforce Winter19(APIVer44)用にメタデータエクスポートツールのバージョンをあげました。

 

ダウンロードはこちらからです。

 

今回からツールにjdkを含めています。というのも、OracleJDKが使えなくなる(有償化される)日が近いうちに来るため、openJDKに慣れておきたいと考えたからです。

 

APIVer43と44では、オブジェクト情報にChangeDataCaptureの情報が追加されていたり、ダッシュボードのコンポーネントで数字の小数点の情報などが追加されていたりなど多少違いがありました。

 

最後に

Salesforceの周辺ツール(DataLoaderやforce.com IDE、移行ツールなど)JDKの有償化や、JDK9から32bit版がなかったりなどJavaに関連する対応が気になります。

全く先が読めないですが、これから大変になっていくんですかね。。

Salesforce: 階層を持つフォルダとそのフォルダのレポート・ダッシュボードをデプロイする

Summer18からレポート・ダッシュボードフォルダは階層を持つことができるようになりました。

 

変更セットを使えば、フォルダの階層関係とレポート・ダッシュボードをそのまま他の組織にリリースできます。(サブフォルダは更新できませんので変更セットでもリリース先にフォルダがあるとエラーになります)

が、メタデータからのデプロイでは次の問題があります。

メタデータからのデプロイの問題点

  • サブフォルダとサブフォルダ内のレポート・ダッシュボードは、retrieveしたZipファイルをそのままdeployできずpackage.xmlの編集が必要

問題点の詳細と対策

そもそもメタデータでretrieveすると次のようになります。
例として、フォルダ「Lv1」の下にフォルダ「Lv2」、フォルダ「Lv2」の下にはレポート「Lv2Report」という構成とします。

f:id:crmprogrammer38:20181021185518p:plain

retrieveしたメタデータ

f:id:crmprogrammer38:20181021190458p:plain


Salesforceのフォルダ階層と同じように、メタデータのフォルダも階層となっています。(※workbenchで取得したためunpackagedフォルダがルートにありますが、Force.com IDEや、Ant移行ツールでは多少違いがあります)


そして、package.xmlは次のようになります。

<!--?xml version="1.0" encoding="UTF-8"?-->

<package xmlns="http://soap.sforce.com/2006/04/metadata">

    <types>

        <members>Lv1</members>

        <name>Report</name>

    </types>

    <types>

        <members>Lv2</members>

        <name>Report</name>

    </types>

    <types>

        <members>Lv2/Lv2Report</members>

        <name>Report</name>

    </types>

    <version>43.0</version>

</package>

問題の詳細ですが、

  • Lv2フォルダは、Lv1のサブなので本来であれば「Lv1/Lv2」なのですが、retrieveしたpackage.xmlでは「Lv2」となっていること
  • 同様に、Lv2Reportレポートも本来であれば「Lv1/Lv2/Lv2Report」なのですが、retrieveしたpackage.xmlでは「Lv2/Lv2Report」となっていること
  • サブフォルダは、Deployで更新すると「このフォルダの一意の名前はこのフォルダ種別ですでに使用されているか、以前に使用されていました。別の名前を選択してください。」のエラーが発生します。(これは変更セットでも同様です)

 

上記を踏まえると、deployする前には次のようにpackage.xmlの編集が必要です。

<!--?xml version="1.0" encoding="UTF-8"?-->

<package xmlns="http://soap.sforce.com/2006/04/metadata">

    <types>

        <members>Lv1</members>

        <name>Report</name>

    </types>

    <types>

        <members>Lv1/Lv2</members>

        <name>Report</name>

    </types>

    <types>

        <members>Lv1/Lv2/Lv2Report</members>

        <name>Report</name>

    </types>

    <version>43.0</version>

</package>

フォルダ構成を押さえておいて、サブフォルダやサブフォルダのレポートのコンポーネントにトップレベルからのフォルダの記載をする必要があります。

そして、deploy先にサブフォルダが既に存在する場合は次のようにpackage.xmlの記載から削除しておく必要があります。

<!--?xml version="1.0" encoding="UTF-8"?-->

<package xmlns="http://soap.sforce.com/2006/04/metadata">

    <types>

        <members>Lv1</members>

        <name>Report</name>

    </types>

<!--
<types> <members>Lv1/Lv2</members> <name>Report</name> </types>
--> <types> <members>Lv1/Lv2/Lv2Report</members> <name>Report</name> </types> <version>43.0</version> </package>

 レポートフォルダを例としましたが、ダッシュボードフォルダも同様です。

最後に

まだフォルダが階層を持てるようになってから期間が短いので、メタデータのretrieveが最新の仕様に追い付いていない状況です。

モジュールのバックアップとしてメタデータを取得しておいて、うっかり削除してしまった際にはバックアップしたメタデータをdeployして元に戻す運用にしている場合があります。

ですが、レポート・ダッシュボードでフォルダを階層にしている場合、上記の問題がありそのままでは復旧できないので注意が必要です。

また、参考としてAPI43以上であればフォルダ(Folder)オブジェクトに、Folder ID(ParentId )項目があるので、DataLoaderで取得した後にフォルダの階層情報をたどることができます。※Folder IDには参照先名がないので、SOQLで参照先をたどって取得はできないようです。