Data Format Component Apache Camel コンポーネント開発 @ssogabe 概要 • Apache Camelがサポートするデータフォーマットを 変換するData Formatコンポーネントの仕組みを理解し、 簡単なコンポーネントを作成する。 • 題材として、Amateras Projectが提供するXLSBeansを 使用し、Excelで作成された定型フォーマットからデー タを読み取り、JavaBeansに変換する。 Data Formatとは • EIPにおけるMessage Translator(メッセージ変換)を 提供する仕組み • Camelでは、コンポーネントとして、以下のコンポーネ ントを提供 • • • • • Bindy JAXB Zip Jackson ... 使用例 • JAXBコンポーネントを使って、XML⇔JavaBeans <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <dataFormats> <!– JAXBのオプション設定 --> <jaxb id="myJaxb" prettyPrint="true" /> </dataFormats> <!– JavaBeans ⇒ XML --> <route> <from uri="direct:start"/> <marshal ref="myJaxb"/> <to uri="direct:marshalled"/> </route> <!– XML ⇒ JavaBeans --> <route> <from uri="direct:marshalled"/> <unmarshal ref="myJaxb"/> <to uri="mock:result"/> </route> </camelContext> <marshal> <jaxb prettyPrint=“true” /> </marshal> でもOK XLSBeansとは • Amateras Projectが提供する、アノテーションを付与し たJava BeansとExcelをマッピングするライブラリ @Sheet(name = "UserList") public class UserList { シートの定義 @LabelledCell(label = "title", type = LabelledCellType.Right) public String title; } @HorizontalRecords(tableLabel = "User List", recordClass = User.class) public List<User> users; public class User { @Column(columnName = "id") public int id; @Column(columnName = "name") public String name; UserList userList = (UserList) XMLSBeans().load( new FileInputStream(“user.xlsx”), UserList.class) for (User user : userList.users) { @Column(columnName = "age") public int age; ...... } リストに含まれるユーザの定義 @Column(columnName = "gender") public String gender; } シートをマッピング 仕様 • 変換対象となるExcelファイルは、Fileコンシューマーな どで取得し、ExchangeのBODYに設定 • Spring XMLで、Excelファイルから変換するJavaBeans の完全修飾名(objectType)を指定 • XLSX形式のみサポート <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:unmarshal"/> <unmarshal> <custom ref="xlsBeansDataFormat" /> </unmarshal> <to uri="mock:unmarshal" /> </route> </camelContext> <bean id="xlsBeansDataFormat" class=“jp.co.nttcom.eai.component.xlsbeans.XLSBeansDataFormat" > <property name="objectType" value="jp.co.nttcom.eai.model.UserList" /> </bean> Maven Projectの作成 (1) • mvn archetype:generate を実行し、CamelのData Format向け Maven Projectの雛形を生成 C:\mvn archetype:generate \ -DarchetypeGroupId=org.apache.camel.archetypes \ -DarchetypeArtifactId=camel-archetype-dataformat \ -DarchetypeVersion=2.13.2 \ -DgroupId=osseai \ -DartifactId=xlsbeans \ -Dversion=1.0-SNAPSHOT \ -Dpackage=jp.co.nttcom.eai.component.xlsbeans \ -Dname=XLSBeans \ -Dscheme=xlsbeans • mvn eclipse:eclipse を実行し、Eclipseの.classpathなどのファイル を作成 Maven Projectの作成 (2) • 以下のディレクトリ、ファイルが生成される 依存ライブラリの追加 • XLSBeansを使用できるようにpom.xmlを修正 <dependencies> (snip) <dependency> <groupId>jp.sf.amateras.xlsbeans</groupId> <artifactId>xlsbeans</artifactId> <version>1.2.5</version> </dependency> (snip) </dependencies> <repositories> <repository> <id>amateras</id> <name>Project Amateras Maven2 Repository</name> <url>http://amateras.sourceforge.jp/mvn/</url> </repository> </repositories> ビルドの確認 • ビルドできることを確認する C:\xlsbeans\mvn package [INFO] Scanning for projects... [INFO] [INFO] -----------------------------------------------------------------------[INFO] Building Camel XLSBeans Data format 1.0-SNAPSHOT [INFO] -----------------------------------------------------------------------(snip) [INFO] [INFO] --- maven-jar-plugin:2.3.2:jar (default-jar) @ xlsbeans --[INFO] Building jar: c:\home\tmp\xlsbeans\target\xlsbeans-1.0-SNAPSHOT.jar [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESS [INFO] -----------------------------------------------------------------------[INFO] Total time: 13.370s [INFO] Finished at: Wed Jul 16 10:52:18 JST 2014 [INFO] Final Memory: 7M/17M [INFO] ------------------------------------------------------------------------ DataFormatインタフェース • Excel⇔JavaBeansを行うメソッドを提供 • 必須のインタフェース package org.apache.camel.spi; public interface DataFormat { // JavaBeans の変換 今回は実装しない void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception; // Excel ⇒ JavaBeansの変換を行う // streamは、Excelファイルのストリーム形式 Object unmarshal(Exchange exchange, InputStream stream) throws Exception; } ServiceSupportクラス • コンポーネントのライフサイクルを制御するクラス • インスタンスの生成など、初期処理、終了処理が必要な 場合は、このクラスを継承する package org.apache.camel.support; public abstract class ServiceSupport implements StatefulService { // 初期処理 protected abstract void doStart() throws Exception; } // 終了処理 protected abstract void doStop() throws Exception; CamelContextAwareインタフェース • CamelContextが必要な場合に実装 • Camel本体がCamelContextをインジェクト • 今回は使用しない package org.apache.camel; public interface CamelContextAware { // CamelContextの設定 void setCamelContext(CamelContext camelContext); // CamelContextの取得 CamelContext getCamelContext(); } XLSBeansDataFormatの実装(1) • パラメータはフィールドとして定義 • objectTypeの確認とXLSBeansのインスタンスを生成 public class XLSBeansDataFormat extends ServiceSupport implements DataFormat { private Class objectType; // setter/getterは必要 private XLSBeans xlsBeans; @Override protected void doStart() throws Exception { // objectTypeは必須 ObjectHelper.notNull(objectType, "objectType"); xlsBeans = new XLSBeans(); } @Override protected void doStop() throws Exception { // do nothing } XLSBeansDataFormatの実装(2) • unmarshalのみ実装 • XLSBeansのインスタンスは、スレッドで共有しても問 題ないので、先に生成しておく @Override public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception { } throw new UnsupportedOperationException("Not supported yet."); @Override public Object unmarshal(Exchange exchange, InputStream stream) throws Exception { } } // XLSX形式のみ対応(固定) return xlsBeans.load(stream, objectType, WorkbookFinder.TYPE_XSSF); テストライブラリの追加 • Camelでは、いくつかのテストをサポートするライブラ リを提供 • Spring XMLで作成したルートをテストするために、 pom.xmlに以下を追加 <dependencies> (snip) <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-test-spring</artifactId> <version>2.13.2</version> <scope>test</scope> </dependency> (snip) </dependencies> テスト資材の配置 (1) • テスト対象のExcelファイルuserlist.xlsxを、 src\test\resources\jp\co\nttcom\eai\component \xlsbeansに配置 タイトル部分(背景が水色)は 変更しないこと シート名 は”UserList” テスト資材の配置 (2) • src\test\jp\co\nttcom\eai\modelに配置 • Excelシートをマッピングするクラスを作成 package jp.co.nttcom.eai,model; (snip) シート名 @Sheet(name = "UserList") public class UserList { 内容が”title”のセルの右側の セルの値をtitleに設定 @LabelledCell(label = "title", type = LabelledCellType.Right) public String title; } @HorizontalRecords(tableLabel = "User List", recordClass = User.class) public List<User> users; “User List”のセルの下にある表の行の内 容をUserクラスにマッピングする テスト資材の配置 (3) • “User List”テーブルの1行の情報をマッピングするUserク ラスを作成 package jp.co.nttcom.eai,model; (snip) public class User { “id”列の値をマッピング @Column(columnName = "id") public int id; @Column(columnName = "name") public String name; @Column(columnName = "gender") public String gender; @Column(columnName = "age") public int age; } テストするルートの作成 • テストするルートは、”テストクラス名”-context.xml • テストクラス名がXLSBeansDataFormatTest.javaの場合は、 XLSBeansDataFormatTest-context.xml • Excelシートと同じディレクトリに配置する。 <?xml version="1.0" encoding="UTF-8" ?> <beans ... > <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:unmarshal"/> <unmarshal> <custom ref="xlsBeansDataFormat" /> </unmarshal> <to uri="mock:unmarshal" /> </route> </camelContext> <bean id="xlsBeansDataFormat" class=“jp.co.nttcom.eai.component.xlsbeans.XLSBeansDataFormat" > <property name="objectType" value="jp.co.nttcom.eai.model.UserList" /> </bean> </beans> テストクラスの作成(1) • 作成したExcelファイル、ルートを使用したテストクラ ス(XLSBeansDataFormatTest)を作成 package jp.co.nttcom.eai.component.xlsbeans; (snip) @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class XLSBeansDataFormatTest { @Produce(uri = "direct:unmarshal") private ProducerTemplate template; @EndpointInject(uri = "mock:unmarshal") private MockEndpoint mock; : extends ... は不要 テストルートの”<from uri=“direct:unmarshal”/>”に データを送付するためのオブジェクト。 インジェクトされる テストルートの ” <to uri=“mock:unmarshal” />”のモック テストクラスの作成(2) • <to uri=“mock:unmarshal” />が受け取るBODYが、 UserListのインスタンスであることなどを確認 @Test public void testUnmarshal() throws Exception { // 期待値の設定 // Exchangeを1つ受け取り、BODYがUserListのインスタンスであること mock.expectedMessageCount(1); mock.message(0).body().isInstanceOf(UserList.class); // テスト用のExcelファイルを、BODYとして送信する String fileName = getClass().getResource("userlist.xlsx").getFile(); template.sendBody(new File(fileName)); // 期待値を満たしていることを確認 mock.assertIsSatisfied(); } // BODYを取得して、タイトル、Userの数を確認 UserList userList = mock.getReceivedExchanges().get(0).getIn().getBody(UserList.class); assertThat(userList.title, is("ユーザリスト")); assertThat(userList.users, hasSize(5)); 演習1 Excel形式の指定 • 入力のExcel形式(bookType)を選択可能とする。 • “HSSF” Excel 2003形式 拡張子 .xls (Apache POI) • “XSSF” Excel 2007形式 拡張子 .xlsx (Apache POI) • “JXL” Excel 2003形式 拡張子 .xls (Java Excel API) @Override ここを設定可能とする public Object unmarshal(Exchange exchange, InputStream stream) throws Exception { } } // XLSX形式のみ対応(固定) return xlsBeans.load(stream, objectType, WorkbookFinder.TYPE_XSSF); 演習2 XLSBeansConfig • 読み込んだ文字列のトリムなど、読み込み時の動作をカ スタマイズ可能とする XLSBeans xlsBeans = new XLSBeans(); // 読み込み時の動作を設定する情報 XLSBeansConfig config = new XLSBeansConfig(); // 文字列をtrim config.setTrimText(trim); xlsBeans.setConfig(config); <bean id="xlsBeansDataFormat" class=“jp.co.nttcom.eai.component.xlsbeans.XLSBeansDataFormat" > <property name="objectType" value=“jp.co.nttcom.eai.component.xlsbeans.UserList" /> <property name="bookType" value="XSSF" /> <property name="config" ref="config" /> </bean> <bean id="config" class="net.java.amateras.xlsbeans.XLSBeansConfig" > <property name="trimText" value="true" /> </bean> モデラーでのコンポーネント • Spring XMLをもとに、モデラーのコンポーネントをどの ように提供するか検討する <camelContext xmlns="http://camel.apache.org/schema/spring"> データ変換として提供 <route> <from uri="direct:unmarshal"/> <unmarshal> <custom ref="xlsBeansDataFormat" /> </unmarshal> <to uri="mock:unmarshal" /> 共有できるので、データ変換 </route> </camelContext> のオプションとして提供 objectTypeはパラメータ <bean id="xlsBeansDataFormat" class=“jp.co.nttcom.eai.component.xlsbeans.XLSBeansDataFormat" > <property name="objectType" value="jp.co.nttcom.eai.model.UserList" /> </bean>
© Copyright 2024 ExpyDoc