Show Table of Contents
第7章 出力データのリッチ化
出力データをリッチ化するためにすぐ使用できる方法は次の 3 つになります。
JDBC データソースを使用してデータベースにアクセスし、SQL ステートメントを使用してデータベースへ読み書きします。この機能は、 Smooks のルーティングカートリッジより提供されます。「SQL を用いたデータベースへのルーティング」の項を参照してください。
エンティティ永続化フレームワーク (Ibatis、Hibernate、JPA 互換フレームワークなど) を使用してデータベースへアクセスし、そのクエリ言語か CRUD メソッドを使用してデータベースへ読み書きします。「エンティティ永続化フレームワーク」の項を参照してください。
カスタムのデータアクセスオブジェクト (DAO) を使用してデータベースにアクセスし、その CRUD メソッドを使用してデータベースへ読み書きします。「DAO サポート」の項を参照してください。
Smooks 1.2 の新しい Smooks 永続カートリッジでは、 Smooks 内より複数のエンティティ永続フレームワークを直接使用することができます (Hibernate、JPA など)。
Hibernate の例を見てみましょう。 別のJPA 対応フレームワークでもプリンシパルは同じです。
この例で処理されるデータは XML 注文メッセージですが、 入力データは CSV、JSON、EDI、Java、これ以外の構造化/階層化されたデータ形式でも可能です。 データの形式に関係なく、同じプリンシパルが適用されます。
<order>
<ordernumber>1</ordernumber>
<customer>123456</customer>
<order-items>
<order-item>
<product>11</product>
<quantity>2</quantity>
</order-item>
<order-item>
<product>22</product>
<quantity>7</quantity>
</order-item>
</order-items>
</order>
Hibernate のエンティティは次の通りです。
@Entity
@Table(name="orders")
public class Order {
@Id
private Integer ordernumber;
@Basic
private String customerId;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List orderItems = new ArrayList();
public void addOrderLine(OrderLine orderLine) {
orderItems.add(orderLine);
}
// Getters and Setters....
}
@Entity
@Table(name="orderlines")
public class OrderLine {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@ManyToOne
@JoinColumn(name="orderid")
private Order order;
@Basic
private Integer quantity;
@ManyToOne
@JoinColumn(name="productid")
private Product product;
// Getters and Setters....
}
@Entity
@Table(name = "products")
@NamedQuery(name="product.byId", query="from Product p where p.id = :id")
public class Product {
@Id
private Integer id;
@Basic
private String name;
// Getters and Setters....
}
この例では、注文の処理と永続化を行います。最初に、注文データを注文エンティティ (Order、OrderLine および Product) へバインドする必要があります。バインドするには以下が必要となります。
- Java Binding フレームワークを使用して Order エンティティと OrderLine エンティティを作成し投入します。
- 各 OrderLine インスタンスを Order インスタンスへワイヤリングします。
- 各 OrderLine インスタンス内で、関連する注文行の Product エンティティをルックアップしワイアリングする必要があります。
- 最後に、Order インスタンスを挿入 (永続化) する必要があります。
これには、 次の Smooks 設定が必要になります。
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.4.xsd"
xmlns:dao="http://www.milyn.org/xsd/smooks/persistence-1.2.xsd">
<jb:bean BeanId="order" class="example.entity.Order" createOnElement="order">
<jb:value property="ordernumber" data="ordernumber" />
<jb:value property="customerId" data="customer" />
<jb:wiring setterMethod="addOrderLine" BeanIdRef="orderLine" />
</jb:bean>
<jb:bean BeanId="orderLine" class="example.entity.OrderLine" createOnElement="order-item">
<jb:value property="quantity" data="quantity" />
<jb:wiring property="order" BeanIdRef="order" />
<jb:wiring property="product" BeanIdRef="product" />
</jb:bean>
<dao:locator BeanId="product" lookupOnElement="order-item" onNoResult="EXCEPTION" uniqueResult="true">
<dao:query>from Product p where p.id = :id</dao:query>
<dao:params>
<dao:value name="id" data="product" decoder="Integer" />
</dao:params>
</dao:locator>
<dao:inserter BeanId="order" insertOnElement="order" />
</smooks-resource-list>
クエリ文字列の代わりに productById という名前のクエリを使用したい場合は、 DAO ロケーターを次のように設定します。
<dao:locator BeanId="product" lookupOnElement="order-item" lookup="product.byId" onNoResult="EXCEPTION" uniqueResult="true">
<dao:params>
<dao:value name="id" data="product" decoder="Integer"/>
</dao:params>
</dao:locator>
次のコードは Smooks を実行します。SessionRegister オブジェクトを使用するため、Smooks 内より Hibernate セッションへアクセスできることに注意してください。
Smooks smooks = new Smooks("smooks-config.xml");
ExecutionContext executionContext = smooks.createExecutionContext();
// The SessionRegister provides the bridge between Hibernate and the
// Persistence Cartridge. We provide it with the Hibernate session.
// The Hibernate Session is set as default Session.
DaoRegister register = new SessionRegister(session);
// This sets the DAO Register in the executionContext for Smooks
// to access it.
PersistenceUtil.setDAORegister(executionContext, register);
Transaction transaction = session.beginTransaction();
smooks.filterSource(executionContext, source);
transaction.commit();
ここで DAO ベースの例を見てみましょう。この例は、注文情報が含まれている XML ファイルを読み取ります (EDI や CSV などでも同じように動作します)。 javabean カートリッジを使用して、 XML データをエンティティ Bean のセットへバインドします。 注文商品内の商品 ID を使用して (product 要素)、 商品エンティティを見つけ、order エンティティ Bean へバインドします。 最終的に注文 Bean が永続化されます。
注文の XML メッセージは次のようになります。
<order>
<ordernumber>1</ordernumber>
<customer>123456</customer>
<order-items>
<order-item>
<product>11</product>
<quantity>2</quantity>
</order-item>
<order-item>
<product>22</product>
<quantity>7</quantity>
</order-item>
</order-items>
</order>
次のカスタム DAO は Order エンティティを永続化するために使用されます。
@Dao
public class OrderDao {
private final EntityManager em;
public OrderDao(EntityManager em) {
this.em = em;
}
@Insert
public void insertOrder(Order order) {
em.persist(order);
}
}
このクラスを検証すると、
@Dao アノテーションと @Insert アノテーションがあることが分かります。 @Dao アノテーションは OrderDao が DAO オブジェクトであることを宣言します。 @Insert アノテーションは insertOrder メソッドを使用して Order エンティティを挿入すべきであることを宣言します。
次のカスタム DAO は、Product エンティティを検索するために使用されます。
@Dao
public class ProductDao {
private final EntityManager em;
public ProductDao(EntityManager em) {
this.em = em;
}
@Lookup(name = "id")
public Product findProductById(@Param("id")int id) {
return em.find(Product.class, id);
}
}
このクラスを見ると、
@Lookup アノテーションと @Param アノテーションの存在に気付くはずです。@Lookup アノテーションは、 ProductDao#findByProductId メソッドを使用して Product エンティティをルックアップすることを宣言します。 @Lookup アノテーションの name パラメータは、メソッドに対するルックアップ名の参照を設定します。 この名前が宣言されないと、 メソッド名が使用されます。 任意の @Param アノテーションはパラメータを命名できるようにします。 これにより、 Smooks と DAO 間の抽象化が向上されます。 @Param アノテーションが宣言されないと、 パラメータはポジションによって解決されます。
Smooks の設定は次のようになります。
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.4.xsd"
xmlns:dao="http://www.milyn.org/xsd/smooks/persistence-1.2.xsd">
<jb:bean BeanId="order" class="example.entity.Order" createOnElement="order">
<jb:value property="ordernumber" data="ordernumber"/>
<jb:value property="customerId" data="customer"/>
<jb:wiring setterMethod="addOrderLine" BeanIdRef="orderLine"/>
</jb:bean>
<jb:bean BeanId="orderLine" class="example.entity.OrderLine" createOnElement="order-item">
<jb:value property="quantity" data="quantity"/>
<jb:wiring property="order" BeanIdRef="order"/>
<jb:wiring property="product" BeanIdRef="product"/>
</jb:bean>
<dao:locator BeanId="product" dao="product" lookup="id" lookupOnElement="order-item" onNoResult="EXCEPTION">
<dao:params>
<dao:value name="id" data="product" decoder="Integer"/>
</dao:params>
</dao:locator>
<dao:inserter BeanId="order" dao="order" insertOnElement="order"/>
</smooks-resource-list>
次のコードが Smooks を実行します。
Smooks smooks=new Smooks("./smooks-configs/smooks-dao-config.xml");
ExecutionContext executionContext=smooks.createExecutionContext();
// The register is used to map the DAO's to a DAO name. The DAO name isbe used in
// the configuration.
// The MapRegister is a simple Map like implementation of the DaoRegister.
DaoRegister<object>register = MapRegister.builder()
.put("product",new ProductDao(em))
.put("order",new OrderDao(em))
.build();
PersistenceUtil.setDAORegister(executionContext,mapRegister);
// Transaction management from within Smooks isn't supported yet,
// so we need to do it outside the filter execution
EntityTransaction tx=em.getTransaction();
tx.begin();
smooks.filter(new StreamSource(messageIn),null,executionContext);
tx.commit();

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.