PR

JBoss Fuseを使ってみる その3:Webサービス編

2015年4月30日(木)
北東 孝雄

RESTful Webサービス化

CamelルートをRESTful Webサービス化する際には、CXFRSコンポーネントを利用します。手順はSOAPの場合とほぼ同じですので、もう少し中身を実装します。

【手順1】通信で使用するデータフォーマットの設定

RESTful Webサービスの通信で利用するデータフォーマットは、Javaのクラスとして作成します。ここでは、Cutromer.java(リスト5)、CustomerList.java(リスト6)の2つのクラスを作成します。

リスト5:Customer.java

package com.mycompany.wsserver.rest;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;

public class Customer {
        private String id;
        private String firstName;
        private String lastName;
        private int age;
        public Customer(){}
        public Customer(String id, String firstName, String lastName, int age) {
                this.id = id;
                this.firstName = firstName;
                this.lastName = lastName;
                this.age = age;
        }
        public String getId() {
                return id;
        }
        @XmlAttribute
        public void setId(String id) {
                this.id = id;
        }
        public String getFirstName() {
                return firstName;
        }
        @XmlElement
        public void setFirstName(String firstName) {
                this.firstName = firstName;
        }
        public String getLastName() {
                return lastName;
        }
        @XmlElement
        public void setLastName(String lastName) {
                this.lastName = lastName;
        }
        public int getAge() {
                return age;
        }
        @XmlElement
        public void setAge(int age) {
                this.age = age;
        }
        @Override
        public String toString() {
                StringBuilder builder = new StringBuilder();
                builder.append("Customer [id=").append(id).append(", firstName=")
                                .append(firstName).append(", lastName=").append(lastName)
                                .append(", age=").append(age).append("]");
                return builder.toString();
        }
}

リスト6:CustomerList.java

package com.mycompany.wsserver.rest;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="CustomerList")
public class CustomerList {
        private List<Customer> customers;
        public CustomerList(){
                setCustomers(new ArrayList<Customer>());
        }
        public List<Customer> getCustomers() {
                return customers;
        }
        @XmlElement(name="customer")
        public void setCustomers(List<Customer> customers) {
                this.customers = customers;
        }
        public void addCustomer(Customer customer){
                customers.add(customer);
        }
}

XML要素にはjavax.xml.bind.annotation.XmlElementアノテーションを付与します。その他、XmlRootElement、XmlAttributeアノテーションも同様です。

【手順2】インターフェース作成

SOAPの場合と同様にインターフェースを作成します。

リスト7:インターフェースの作成(CustomerEndpoint.java)

package com.mycompany.wsserver.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

public interface CustomerEndpoint {
        @GET
        @Path("/list")
        @Produces("application/xml")
        public CustomerList listCustomer();

        @GET
        @Path("/add/{id}/{firstname}/{lastname}/{age}")
        @Produces("application/xml")
        public CustomerList addCustomer(@PathParam("id") String id, @PathParam("firstname") String firstname, @PathParam("lastname") String lastname, @PathParam("age") int age);
}

javax.ws.rsで提供されている各種アノテーションを付与するところがポイントです。またそれぞれの戻り値として、CustomerListクラスを設定します。

【手順3】データ処理クラス作成

RESTfulインターフェースを介して、Camelルートに入ってきたデータを処理するためのクラスを作成します。上記listCustomerメソッド、addCustomerが呼ばれた際の処理内容を以下のように実装します(リスト8、リスト9)。

リスト8:listCustomerメソッドに対する処理(ListCustomerProcessor.java)

package com.mycompany.wsserver.rest;

import javax.ws.rs.core.Response;
import org.apache.camel.Processor;
import org.apache.camel.Exchange;

public class ListCustomerProcessor implements Processor {

    @Override
    public void process(Exchange exchange) throws Exception {   CustomerList list = new CustomerList ();
        list.addCustomer(new Customer("0001", "一郎", "佐藤", 20));
        list.addCustomer(new Customer("0002", "花子", "鈴木", 24));
        Response r = Response.status(200).entity(list).build();
        exchange.getOut().setBody(r);
    }
}

リスト9:addCustomerメソッドに対する処理(AddCustomerProcessor.java)

package com.mycompany.wsserver.rest;

import java.util.List;
import javax.ws.rs.core.Response;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;

public class AddCustomerProcessor implements Processor {

        @Override
        public void process(Exchange exchange) throws Exception {
                Message message = exchange.getIn();
                @SuppressWarnings("unchecked")
                List<Object> listBody = (List<Object>) message.getBody();

                CustomerList list = new CustomerList();
                String id = (String) listBody.get(0);
                String firstname = (String) listBody.get(1);
                String lastname = (String) listBody.get(2);
                int age = (Integer) listBody.get(3);
                list.addCustomer(new Customer(id,firstname,lastname,age));
                Response r = Response.status(200).entity(list).build();
                exchange.getOut().setBody(r);
        }

}

Camelルート内に処理を埋め込む際には、org.apache.camel.Processorインターフェースを実装したクラスを作成します。このクラスでは、Camelルート内を流れるメッセージのコンテナであるorg.apache.camel.Exchangeクラスを操作します。ExchangeはJBoss Fuseを理解する上で重要なものなので、別途このページの最後で詳説します。また、RESTのレスポンスはjavax.ws.rs.core.Responseクラスを使用しています。

【手順4】Camelルート作成

ここまでに作成したJavaプログラムを利用する形で、以下のような新しいCamelルートを作成します。

RESTサーバーのCamelルート設定

設定
RouteContainer/wsserver/src/main/resources/OSGI-INF/blueprint
File namerestServer.xml
FrameworkOSGi Blueprint

Designモード

RESTサーバーのCamelルート

図9:RESTサーバーのCamelルート

リスト10:RESTサーバー(Sourceモード)

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
       xmlns:camel="http://camel.apache.org/schema/blueprint"
       xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
       http://camel.apache.org/schema/blueprint/cxf http://camel.apache.org/schema/blueprint/cxf/camel-cxf.xsd
       http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">

  <cxf:rsServer id="restServer" address="/customer"/>
  <bean id="listCustomerProcessor" class="com.mycompany.wsserver.rest.ListCustomerProcessor"/>
  <bean id="addCustomerProcessor" class="com.mycompany.wsserver.rest.AddCustomerProcessor"/>
  <camelContext trace="false" xmlns="http://camel.apache.org/schema/blueprint">
    <route>
        <from uri="cxfrs:bean:restServer?resourceClasses=com.mycompany.wsserver.rest.CustomerEndpoint"/>
        <choice>
            <when>
                <simple>${in.header.operationName} == 'listCustomer'</simple>
                <process ref="listCustomerProcessor"/>
                <log message="${body}"/>
            </when>
            <when>
                <simple>${in.header.operationName} == 'addCustomer'</simple>
                <process ref="addCustomerProcessor"/>
                <log message="${body}"/>
            </when>
        </choice>
    </route>
</camelContext>
</blueprint>

強調している行が、RESTサービスの設定です。SOAPの場合、参照クラスは別箇所で設定しましたが、RESTの場合は、URIに記述する点に注意してください。Javaによる実装を参照する場合には、を用います。参照先はで外出しにする点をご確認ください。また、条件判定で使用している${in.header.operationName}は、インターフェースCustomerEndpointに設定されているメソッド名です。

【手順5】ビルド、インストール、確認

ビルドや設定の確認方法は、全てSOAPの場合と同様です。JBoss Fuseへのインストールについてはすでにインストール済みなので、アップデートを行います。先ほどのBundle IDを控えていればそれを利用できますが、ない場合は、osgi:listコマンドで確認できます。特に作業をしていなければ、一番下に表示されるOSGiバンドルが該当のものなので、そのBundle IDを用いてosgi:updateを行います。

JBossFuse:admin@root> osgi:list
START LEVEL 100 , List Threshold: 50
   ID   State         Blueprint      Spring    Level  Name
[  66] [Active     ] [Created     ] [       ] [   50] Fabric8 :: Karaf Commands (1.0.0.redhat-379)
・・・ (全てのOSGiバンドルが表示される)
[ 305] [Active     ] [            ] [       ] [   60] wrap_mvn_org.postgresql_postgresql_9.3-1100-jdbc41 (0)
 [ 334] [Active     ] [Created     ] [       ] [   60] WS Server (1.0.0.SNAPSHOT)
JBossFuse:admin@root> osgi:update 334
JBossFuse:admin@root>

「http://localhost:8181/cxf」では、以下のように確認できます(図14)。

RESTサーバーの確認

図10:RESTサーバーの確認

WADLも自動的に生成されているのが分かります。動作確認はブラウザを利用して行えます。

List(http://localhost:8181/cxf/customer/list)のレスポンス

図11:List(http://localhost:8181/cxf/customer/list)のレスポンス

Add(http://localhost:8181/cxf/customer/add/10/test/sample/20)処理のレスポンス

図12:Add(http://localhost:8181/cxf/customer/add/10/test/sample/20)処理のレスポンス

Exchangeについて

Exchangeは、Camelルート内を流れるメッセージのコンテナです。下図のような構成となっています。

Exchangeの構成

図13:Exchangeの構成

Exchangeの構成要素一覧

項目概要
ExchangeIDCamelが自動採番するID
Exceptionエラー発生時に設定される
MEP(Message Exchange Pattern)InOnly(片方向)、InOut(双方向)
Propertiesルート全体のプロパティ
In Messageメッセージを保持する
Out MessageMEPがInOutの時だけ存在する。
応答メッセージを保持する。

この中のIn Message、Out MessageのMessage(org.apache.camel.Message)は、次のような構造になっています。

Messageの構成

図14:Messageの構成

Messageの構成要素一覧

項目概要
Headersヘッダ情報。java.util.Mapで実装されている
AttachmentsWebサービスやe-mailなどで使用されるアタッチメント
Bodyメッセージが運ぶデータ本体。データ型はObjectとして定義されている。
faultフラグoutputとfaultを区別するためのフラグ

Apache Camelは、Camelルートの中でこのExchangeに含まれるMessageを加工していくことで処理を行います。

Camelルート処理イメージ

図15:Camelルート処理イメージ

図11のようなCamelルートがある場合、Exchangeは次のように動きます(一例です)。

Exchangeの推移

図16:Exchangeの推移

各EndpointやProcessorにおいて、Out Messageがnullの場合、In Messageが次の処理にそのまま引き継がれます。一方Out Messageに値が入っている場合、その値がそのまま次の処理のIn Messageとなります。Out Messageに値が入ってくるかどうかは、MEPの設定に依存する場合があります。MEPが「InOnly」の設定になっている場合(多くのEndpointでデフォルト設定)、Camelは処理を呼び出して、そのレスポンスを受け取りません。また、上記ルートでConsumer Endpointが「InOut」の設定になっている場合、Consumer Endpointに返される内容は、Producer EndpointのOut Messageになります。

レッドハット株式会社

JBossサービス事業部 JBossコンサルタント
大学にて哲学を専攻後、沖電気工業、日本ティブコソフトウェアを経て、2013年にレッドハットに入社。主にインテグレーション系製品のコンサルティングサービスに従事。

連載バックナンバー

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

他にもこの記事が読まれています