SalesforceのSummer15のリリースでLightning Connectが利用できるようになったようなので
ODataの勉強がてら触ってみましたー。
Lightning Connectは任意のOData Providerが提供するODataサービスを使って
Salesforceから外部データをCRUDできますよーっていう機能。
OData自体はインターフェースが仕様に準拠していれば裏はなんでもOKっていう
HTTP版ODBC的なプロトコルです。
ODataに関しては以下のリンクが詳しいです。
SFDCでのLightning Connectの設定に関しては以下のリンクが詳しいです。
Lightning Connectを手軽に試してみる « TerraSky Tech Blog
今回は自前でOData Providerを作って、それに対してSFDCから接続してみます。
以下のリンクが自前でクライアント、サーバ側を構築する際のライブラリになります。
Libraries · OData - the Best Way to REST
今回はJavaのApache Olingo Libraryを使ってサンプルをベースにOData Providerを作っていきます。
※ちなみにOData全然知らないので解説で所々間違いが有ると思いますのでご注意を!
0. 準備
JDKとかmavenとかインストールしておきます。1. サンプルのmavenプロジェクトを作成
SFDCでは現時点(2015/05/15)ではOData v2.0にしか対応していないのでv2.0のチュートリアルに従って進めていきます。
まず、Sample Project Setupに従って以下のmvnコマンドを実行します。
mvn archetype:generate \
-DinteractiveMode=false \
-Dversion=1.0.0-SNAPSHOT \
-DgroupId=com.sample \
-DartifactId=my-car-service \
-DarchetypeGroupId=org.apache.olingo \
-DarchetypeArtifactId=olingo-odata2-sample-cars-service-archetype \
-DarchetypeVersion=RELEASE
プロジェクトがいい感じに作成されたら、ビルドします。
cd my-car-service
mvn clean install
そうするといい感じにtarget内にwarが出来上がるので
このwarをtomcatとかのwebのルートにデプロイすればセルフなOData Providerが動きます。
herokuでwarを動かしたい場合はpom.xmlのpluginにwebapp-runnerを追加して、Procfileに
web: java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war
と書いてpushすればOK。herokuでwar動かす時の詳細は以下を参照。
https://devcenter.heroku.com/articles/java-webapp-runner
2. サンプルの説明
ソースを見ると4つクラスがあり、それぞれ以下のような役割を持っています。CarDataStore.java : データストアのクラス(必須ではないけど、役割的に分けている)
CarEdmProvider.java : Entity Data Model Providerでメタデータ表示したり管理したり
CarODataSingleProcessor.java : データ読み書きを管理する。
CarServiceFactory.java : サービスファクトリ。ここからサービスが起動する。
CarEdmProvider.java
OData Providerではクライアントが適切にサービスを利用できるようにフィードを取得できるURIやエンティティのプロパティやリレーション等の
スキーマ定義などを外部に公開します。
それらの情報を定義するクラスがEdmProviderになります。
スキーマの例は以下のリンクで見ることが出来ます。
http://services.odata.org/V2/OData/OData.svc/
http://services.odata.org/V2/OData/OData.svc/$metadata
これらのXML(ODataではCSDLと呼びます)をJavaでゴリゴリ書いていく感じです。
CSDLに関する詳細仕様は以下を参照ください。(何故かversion2のドキュメントが無かった…)
http://www.odata.org/documentation/odata-version-3-0/common-schema-definition-language-csdl/
サンプルのCarEdmProviderではEdmProviderを継承しており、
EdmProviderの各メソッドをオーバーライドしています。
それぞれのメソッドは以下のような役割を持ちます。
getSchemas → スキーマ全体の定義
getEntityType → 個々のエンティティに関するスキーマを定義します。
getComplexType → 複合項目(プリミティブのセット)の定義をします。
getAssociation → エンティティのリレーションを定義します。
getEntitySet → エンティティの集合の定義をします。
getAssociationSet → リレーションのセットを定義します。
getFunctionImport → 抽出用の関数を定義します。ストアドプロシージャみたいな感じです。
getEntityContainerInfo → EntitySetとAssociationSetを定義します。
CarODataSingleProcessor.java
読み書きに関するオペレーションの定義を行います。ODataSingleProcessorクラスを継承しており、各メソッドをオーバーライドしています。
サンプルでは以下のメソッドをオーバーライドしており、それぞれ以下の役割を持ちます。
readEntitySet → 複数フィードのエンティティの読み取り
readEntity → 単数フィードのエンティティの読み取り
CarServiceFactory.java
OData serviceのファクトリクラスです。サンプルの{ROOT}/WEB-INF/web.xml内に
...
<servlet>
<servlet-name>CarServiceServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.apache.olingo.odata2.core.rest.app.ODataApplication</param-value>
</init-param>
<init-param>
<param-name>org.apache.olingo.odata2.service.factory</param-name>
<param-value>com.sample.CarServiceFactory</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CarServiceServlet</servlet-name>
<url-pattern>/CarService.svc/*</url-pattern>
</servlet-mapping>
...
という記述があり、CXFNonSpringJaxrsServletにODataApplicationとCarServiceFactoryを
パラメータとして渡して、サーブレットをマッピングすることで
OData ProviderとしてWebアプリケーションを起動させています。
CarServiceFactoryはODataServiceFactoryクラスを継承しており
createServiceメソッドで上記のEdmProviderとODataSingleProcessorを
パラメータとしてcreateODataSingleProcessorServiceを実行しています。
3. Lightning Connectとの連携
今回はherokuにOData Providerを立ててみたので、それをエンドポイントとして設定していきます。
あとは同期するとこんな感じで外部オブジェクトが作成されます。
サンプルのソースだとCars-Manufacturers間のリレーションが張られないので
手動でManufacturerIdを外部参照にします。
そうするといい感じに参照が張られます。
その他
今回のサンプルではXMLをJavaで書くようなゴリゴリ系でしたがアノテーションを使ってJava Beansで書くような方法もあります。
https://olingo.apache.org/doc/odata2/tutorials/AnnotationProcessorExtension.html
また、CarDataStore.javaでは静的にデータを返してますが、
実際にはこの部分をDBから動的にデータを返却するようにします。
あと、実用には認証機構も必要ですかねー。