freedom-man.com

ブログは俺のセーブポイント

Tag: java

EmbulkのSalesforce outputプラグインを作ってみた。

EmbulkというOSSが非常に気になっていた&Salesforceのoutputプラグインが無かったので、勉強がてら作ってみました。↓

tzmfreedom/embulk-output-salesforce

今回は備忘としてoutputプラグインの作り方と、embulk-output-salesforceの使い方を書いていきます!
Output Pluginの作成は以下のURLを参考にしました。

Java で Embulk Output Plugin を書く – Qiita

ちなみに、ソースコードを全て読んだわけではない&読んだところも合っているか怪しいので、多少間違いが有ると思いますがご了承願います。

outputプラグインの作り方

テンプレートの作成

プラグインはJavaかRubyで書くことが出来ます。今回はJavaを使いました。
プラグインのテンプレートは以下のコマンドで作成できます。

これでGradleベースのプロジェクトが自動生成されます。あとはsrc/main/java/org/embulk/outputにあるJavaファイルを書いていけばOK。

設定ファイルのキー値の設定

Taskクラスを継承したPluginTaskクラスにキー値と属性を指定し

ConfigSource#loadConfig(PluginTask.class)

で実際の設定を取得します。

PluginTaskにはannotationで属性を指定します。任意入力の項目の場合はOptional型で定義します。未指定時のデフォルト設定値はConfigDefaultアノテーションで定義します。文字列のデフォルトを定義する場合は@ConfigDefault(“\”hoge\””)のようにエスケープが必要。

処理の流れ

OutputPluginの処理の流れだけに着目すると

OutputPlugin#transaction

→OutputPlugin#open(→TransactionalPageOutput#add …)

→OutputPlugin#cleanup

といったフローになります(自信なし)

TransactionalPageOutput

OutputPlugin#openではTransactionalPageOutputを継承したクラスを戻り値とします。
openはタスクの数だけ呼ばれるっぽいので、fileのinputプラグインを使って2つのファイルを処理する場合は、openが2回呼ばれて、TransactionalPageOutputのサブクラスのインスタンスが2つ作成されます。

TransactionalPageOutput#addでは引数のPageに実際のレコードが渡されるので、PageをPageReaderに読ませて、PageReaderではスキーマに応じた全カラムに対して処理を行うことになります。100桁くらいの3000行のデータを入れたら、一回のadd呼び出しで110件ちょっとのレコードが格納されていました。

pageReader.getSchema().visitColumns(…)の部分が全カラムに関する処理になり、引数にはColumnVisitorを継承したクラスを入れます(利用がワンタイムなので匿名クラスにしてます)。ColumnVisitorではカラムのデータ型に応じた処理を記載していきます。

Salesforceの場合はTimeStampだけ注意しておけばOKで、pageReaderで取得できるTimeStampの型はorg.joda.time.DateTime型であるため、wscを利用する場合は、データ型をjava.util.Calendar型やjava.util.Date型に変換する必要があります。wscはデータ型によってSOAPのxsi:typeを書き換えるので、SObject#addFieldで入れるObject型は注意が必要です。

テストの方法

pluginのテストの方法としては大きく2つあり、1つ目は実際のembulkコマンドに作ったプラグインを食わせる方法、もう1つはembulkのクラスを使ってJava内で実行するやり方です。

1つ目は

からの

を実行すればプラグインの挙動を確認できます。

2つ目はembulk runでやってることをJavaのコードを書いて実現するやり方です。

参考URLはこちら→Embulkプラグインのテストを楽にやりたい – 今日もプログラミング

embulk-output-salesforceの使い方

基本的には以下のようなoutputの定義を設定ファイルに書けばOKです。

ログインからデータ入力まで全てSOAP APIを使ってます。
内部的にはカラム名=API参照名としてデータを格納しているので、inputプラグインのfileを使う場合、inputには以下のように記述します。

Embulkの良い所はプラガブルなのでS3にCSVファイルを置いて読み込ませるのも、超簡単に出来ます。(embuk-input-s3を利用します)

result_dirを指定すればData Loaderのようにsuccess_.csvとerror_.csvを出す仕様になっています。

プラグインを作ってみた感想

hubotのときもそうでしたが、やっぱり中身のコードをちゃんと読まないとプラグインは書けない感じですね…。読まないと、プラグインのインターフェースのメソッドがどういうときにどう呼ばれるのかがわからないですし、エラーハンドリングとかも書けないですし。
あと、中身のコードを読むことでそのOSSのイズムみたいなものを何となく感じ取って、そのイズムをプラグインに反映させる、というのも大事なような気がしています。今回は数時間読んでみて、勘でコーディングしてtry&errorみたいな感じだったので、ケースによっては全然動かないポンコツプラグインかもしれませんw

感想その2

「Data Connector for Amazon S3」の記事とか、Embulkの図を見てたら、色んなサービスからのデータをtreasuredataに集約して、そこから中間データマート経由でBIツール等でビジュアライゼーションしたり統計学を駆使して解析する、というようなフローにおいて、データを集約する部分を並列処理で高速に実行し、treasuredataへの出力も冪等性を担保して、かつ色んなサービスからのデータを取り込むためにプラガブルにする、というのがEmbulkの役割な気がしています。

なので、基幹システムとか他のDBのデータをSalesforceにデータを入れて、的なETLツールじゃなくて「fluentdのバッチ版」としてデータを集約しているような感じですかね。作ってから気づいたぜ…。

Fiddlerを使ってEclipseとData Loaderをトラッキング

今更ながらEclipseのforce.com IDEやData Loaderが

どのAPIをどのタイミングで叩いているかが気になったので

Fiddlerのプロキシを噛ませてネットワーク通信をトラッキングしてみました。

Fiddlerの証明書のインストール

JavaのキーストアにFiddlerのルート証明書をインストールします。

まず、Fiddlerのルート証明書をFiddlerからエクスポートします。

Fiddlerを起動し、メニューのTools>Fiddler Optionsをクリックします。

Fiddler_top

HTTPSのタブでExport Root Certificate to Desktopボタンをクリックします。

Fiddler_tool

そうすると、デスクトップにFiddlerRoot.cerの名前で証明書がエクスポートされます。

これを以下のコマンドでJavaのキーストアにインポートします。

<JDK_Home>\bin\keytool.exe -import -file C:\Users\<Username>\Desktop\FiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler

パスワードを聞かれるので、適当なパスワードをセットします。

Eclipseの設定

eclipse.iniの行末に以下の2行を追記します。pathはFiddlerKeyStoreを作った場所をセット。

これでeclipse.exeを起動し、プロキシの設定をします。

ツールバーのWindow>Preferencesをクリックして

GeneralのNetwork Connectionsを開きます。

Fiddlerが起動している状態でNativeを選択すると

以下のように127.0.0.1:8888を向いている状態になります。

eclipse_proxysetting

これでEclipseのHTTP/HTTPS通信をFiddlerでトラッキングできます。

Data Loaderの設定

以下のコマンドでData Loaderを起動します。

Data Loaderに同梱されているJavaを使わないとバージョンの差異等でエラーになる可能性があります。

あとは、起動後のData Loaderのプロキシ設定をすればOK。

dataloader_proxysetting

実際のトラフィック

Data Loaderだとログインした瞬間にdescribeGrobalしてるのがわかります。

Fiddler_dataloader

Eclipseだとrefresh from serverでretrieveしつつポーリングしてる様子がわかります。

Fiddler_eclipse

たまに遅ぇー!ってときがありますが、ちゃんと仕事してました。

疑ってすみません、Eclipseさん。

Salesforceの代理認証SSOやってみる

SalesforceにはSalesforceへの認証を任意の認証サーバが行えるようになる代理認証機能があります。

これによって、Salesforceのパスワードではなく独自で認証基盤を運用することが可能になります。

 

ということで、代理認証SSOをやってみます!

今回はJava + tomcat + axisな代理認証SOAPサーバを立ててみます。

 

参考URL:

Web サービスを開発する: 第 1 回 Axis2 を使用して、コード・ファースト手法とコントラクト・ファースト手法で Web サービスを開発する

 

1. tomcat、axis、antのセットアップ

tomcatをインストールしてaxis2をダウンロード。

Binary DistributionとWAR Distributionの両方をダウンロードしてください。

WARの方はzip展開してtomcatのwebappsディレクトリに入れてインストールは完了。

 

Binaryの方はSalesforceのwsdlからjavaに変換するために利用します。

antはaarファイルの作成に利用します。

 

2. wsdlからサーバースタブを作成

Salesforceから代理認証用のwsdlを取得(設定>開発>API)

download-auth-wsdl

 

任意のディレクトリで以下のコマンドを実行。

{AXIS2_HOME}にはBinary Distributionのaxis2のパスを入れてください。

 

これでサーバースタブが作成されます。

 

3. スケルトンクラスにロジックを追加

src\com\sforce\soap\authenticationディレクトリのSforceAuthenticationServiceSkeleton.java内の

ToDo: fill this with…のところにロジックを追加します。

今回はテキトーに認証してみます。

パラメータのAuthenticateEクラスからユーザ名とパスワードとログイン要求元IPアドレスを取得して

認証サーバ側(=tomcat+axis2)で認証処理をしてあげて

OKであればtrue、ダメだったらfalseを返してSFDC側はtrueを返された時に認証するようになります。

 

今回はユーザ名が”hoge@fuga.com”、パスワードが”abcdef”のときのみ認証するようにしてます。

 

4. aarにしてデプロイ

生成したスタブファイル群のルートディレクトリにディレクトリ移動して、以下のantコマンドを実行。

そうするとSforceAuthenticationService.aarが出来るのでaxis2にWebインターフェースからデプロイします。

 

まずは{デプロイするサーバのドメイン}/axis2/にアクセスしてAdministrationのリンクをクリック。

axis2-top

 

adminでログインする。(ユーザ名はadminで初期パスワードはaxis2)

axis2-adminlogin

 

adminトップ画面からUpload Serviceのリンクをクリック。

axis2-admin-top

 

aarファイルをアップロードする。

axis2-upload

 

Available Servicesのリンクをクリックしてサービスが正常にアップロードされたことを確認。

axis2-services

 

これでデプロイは完了。

上記のEPRがSOAPのエンドポイントになります。

 

5. Salesforce側のセットアップ

代理認証はSalesforceにお問い合わせして有効化してもらってください。DeveloperEditionでもやってもらえました。

有効化してもらったら 設定>セキュリティのコントロール>シングルサインオン設定 で以下のように編集します。

sfsetting-auth-proxy

代理ゲートウェイURLはEPRを入力、代理認証コールアウト強制実行はチェックを外してください。

 

あとは代理認証対象のプロファイルを選択してシングルサインオンの有効にチェックをつけます。

sfsetting-proxysso-profile

 

代理認証サーバが落ちているとログイン出来なくなってしまうので

システム管理者にはシングルサインオンの有効にチェックをつけない方が良いみたいです。

 

あとはこのプロファイルのユーザでログインしてみて

Salesforceから発行されたパスワードではなく代理認証サーバのロジックで認証されていればOKです。

 

これだけだと単に代理で認証しているだけなんですが

任意のアプリからSFDCにログインコール(SOAPのログインとかRESTのUsername-Passwordフローとか)

を行って認証自体は任意のアプリと連携された代理認証サーバで認証し、sessionIdをfrontdoor.jspに突っ込めば

代理認証機能でシングルサインオンができそうです。

 

あと、今回はtomcatとかaxis2とか結構大掛かりでしたが、結局SOAPで送られてくるデータって

こんな感じでシンプルなんで適当にパースして返してあげればライトな言語

ライトなWebフレームワークでも事足りそうです。

© 2017 freedom-man.com

Theme by Anders NorenUp ↑