Apache CXF は Web サービスの開発、ビルド、デプロイに使用される Web サービス・フレームワークです。CXF は多くの機能をサポートしており、開発者はそれらの機能を使用して Web サービス・ベースのアプリケーションの開発やデプロイを行うことができます。そうした機能の 1 つがロギングです。ここで言うロギングは、実質的には Web サービス・メッセージのロギングを意味します。CXF は標準的な Java ロギング API を使用してメッセージのロギングを行います。この方法により、受信メッセージと送信メッセージの両方のログを取ることができます。メッセージのロギングはクライアント・サイドでもサーバー・サイドでも行うことができます。ロギングによって、サーバーとの間で送受信される実際の SOAP ペイロードを見ることができるため、ロギングは重要であり、デバッグ・ツールとしても役に立ちます。CXF でロギングを実装する場合、インターセプターとフィーチャーという概念を使用します。この記事では、それらの概念を使用して単純に Web サービス・メッセージのロギングを実行する方法について説明します。また、Spring ベースの Bean 構成を使用してメッセージ・ロギングを構成する方法についても説明します。
ここでは、JAX-WS フロントエンド、つまり CXF の API を使用する単純な Web サービスを作成します。Web サービスとしては、オンラインの LMS
(Learning Management System: 学習管理システム) を考えてみましょう。LMS
の機能には通常、ユーザー管理、コース作成、ディスカッション・フォーラム、成績表管理、コンテンツ管理などが含まれます。この記事では、「コース作成」を例として取り上げ、CourseBuilder という単純な Web サービス・クラスを作成します。またこの記事では、単純な Web サービスを作成して JAX-WS エンドポイントとして公開する方法を間接的に示します。ただし基本的な目標は、ロギング・メカニズムを示すことです。この記事ではサーバー・サイドのロギングのみに焦点を絞ります。サーバー・サイドのロギングを理解できると、クライアント・サイドのロギングを容易にエミュレートすることができます。
この Web サービス・クラスは以下のようなものです。
リスト 1. CourseBuilderImpl Web サービス・クラス
@WebService
public class CourseBuilderImpl implements CourseBuilder {
public String createCourse(Course course) {
System.out.println("Course code is " + course.getCode());
System.out.println("Course title is " + course.getTitle());
return "Course created successfully";
}
} |
上記の Web サービス・クラス CourseBuilderImpl は非常に単純です。createCourse メソッドは Course という Bean を引数に取り、コースが適切に作成されたことを示すステータス・ストリングを返します。今度はサービス・メッセージのログをコンソールに表示します。サービス・メッセージは実質的に SOAP ペイロード、つまりメソッド・パラメーターと戻り型という形式による実際のデータを意味しています。ロギング機能を有効にすることで、このペイロードをコンソールに表示することができます。
CXF のインターセプターは SOAP メッセージをインターセプトするコンポーネントです。CXF
のインターセプターは受信メッセージも送信メッセージもインターセプトすることができます。従って、これらのインターセプターをクライアント・アプリケーションで構成することも、サーバー・サイドで構成することも、あるいはその両方で構成することもできます。CXF
にはインターセプターがいくつも組み込まれています。メッセージのロギングを実行するインターセプターとしては、LoggingInInterceptor と LoggingOutInterceptor があります。これらのインターセプターを使用してサーバー・サイドでロギングを実行します。以下のコードはその方法を示しています。
リスト 2. サーバー・コード
public final class Server {
public static void main(String args[]) throws Exception {
CourseBuilderImpl implementor = new CourseBuilderImpl();
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
svrFactory.setAddress("http://localhost:9000/CourseBuilder");
svrFactory.setServiceBean(implementor);
svrFactory.getInInterceptors().add(new LoggingInInterceptor());
svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());
svrFactory.create();
}
}
|
上記のコードは JaxWsServerFactoryBean サーバー・ファクトリー・クラスを使用して CourseBuilder サービスを JAX-WS
エンドポイントとして公開します。ご覧のとおり、このコードは実装クラスとエンドポイントのアドレスを設定しています。create メソッドは、組み込みのスタンドアロン Jetty
サーバーを起動します。このコードの重要な部分は太字で強調してあります。強調した部分では、2 つのインターセプター、つまり LoggingInInterceptor と LoggingOutInterceptor を使用しています。これらがファクトリー・クラスに追加された後、create メソッドが呼び出されます。この強調されたコードにより、受信メッセージと送信メッセージの両方に対してサーバー・サイドのロギング機能が有効になります。クライアント・アプリケーションを実行すると、サーバー・コンソールには以下の出力がログとして表示されます。
図 1. サーバー・コンソール
上記のサーバー・コンソール出力は、受信した SOAP ペイロードと送信した SOAP
ペイロードを示しています。また、ログの内容に関する最大サイズをコンストラクターの中で指定して制御することもできます。サイズはバイト数を表しており、例えば new LoggingInInterceptor(1024) のように指定します。これを見るとわかるように、ロギング・インターセプターを利用すると、サービス・メッセージのロギングが非常に容易になります。また、アノテーションを利用してロギングを実装することもできます。以下のコードはアノテーションとインターセプターを利用してロギングを実装しています。
リスト 3. インターセプター・アノテーションを使用したロギング
@WebService
@InInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingInInterceptor")
@OutInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingOutInterceptor")
public class CourseBuilderImpl implements CourseBuilder {
...
|
@InInterceptors と @OutInterceptors
というアノテーションを使用すると、それぞれ受信インターセプターと送信インターセプターを定義することができます。アノテーションの宣言は、サービス・クラスまたは SEI (Service Endpoint Interface) の中で行います。これらのアノテーションが SEI の中にあると、クライアント・アプリケーションとサーバー・アプリケーションの両方でロギング機能が有効になります。上記のコードでは CourseBuilderImpl サービス実装クラスでアノテーションが宣言されているため、サーバー・サイドのみでメッセージ・ロギングが実行されます。
CXF のフィーチャーの機能はデコレーターとよく似ています。CXF
のフィーチャーは、クライアント、サーバー、バスのコンポーネントに適用されます。フィーチャーは基本的に、クライアント、サーバー、またはバスの機能を拡張します。CXF
にはフィーチャーの実装がいくつか組み込まれており、その 1 つが LoggingFeature クラスです。LoggingFeature クラスは SOAP
メッセージのロギングを実行します。ここでは、先ほど示したサーバー・コードを再度取り上げます。今度はインターセプターの代わりに LoggingFeature クラスを使用します。
リスト 4. ロギング・フィーチャー
public final class Server {
public static void main(String args[]) throws Exception {
CourseBuilderImpl implementor = new CourseBuilderImpl();
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
svrFactory.setAddress("http://localhost:9000/CourseBuilder");
svrFactory.setServiceBean(implementor);
svrFactory.getFeatures().add(new LoggingFeature());
svrFactory.create();
}
}
|
強調されたコードがすべてを語っています。このコードは受信メッセージと送信メッセージの両方、つまりサーバーが受信したメッセージとサーバーが返した応答をログとして記録します。そして
LoggingFeature
クラスはロギング・インターセプターを使用します。ただしインターセプターを直接使用した方が、より詳細な制御が可能です。例えば受信メッセージのみをログに記録し、送信メッセージを記録したくない場合には、LoggingInInterceptor インターセプター・クラスのみを使用すればよく、LoggingFeature クラスを使用する必要はありません。ロギング・インターセプターの場合とまったく同じように、LoggingFeature クラスを使用すると、ロギングの内容のサイズをバイト数で制限することができます。制限サイズを指定するためには、コンストラクターの中で以下のようにします。
リスト 5. サイズ制限を付けたロギング・フィーチャー
public final class Server {
public static void main(String args[]) throws Exception {
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
...
// This will only log upto 1K or 1024 characters
svrFactory.getFeatures().add(new LoggingFeature(1024));
...
}
}
|
また LoggingFeature
クラスを使用すると、ロギング対象のメッセージの出力先を設定することができます。構成により、メッセージ・ロギングの出力先を stdout (コンソール)、stderr
(エラー・コンソール)、またはファイルに設定することができます。出力先は受信メッセージに対しても送信メッセージに対しても設定することができます。以下のコードは LoggingFeature クラスで出力先を使用する場合を示しています。
リスト 6. 出力先を指定したロギング・フィーチャー
public final class Server {
public static void main(String args[]) throws Exception {
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
...
svrFactory.getFeatures().add(
new LoggingFeature("<stdout>", "file://home/myLog.txt"));
...
}
}
|
先ほどとは別の、上記の LoggingFeature コンストラクターは、2 つのストリング・パラメーターを引数に取ります。これらのパラメーターはそれぞれ、受信メッセージと送信メッセージのログの出力先を示します。上記のコードから、受信メッセージのログはコンソールに出力され、送信メッセージのログはファイルに出力されます。
フィーチャーにもアノテーションを使用することができます。@Features
アノテーションを使用すると、フィーチャーを指定することができます。以下のコードは @Features アノテーションの使い方を示しています。
リスト 7. アノテーションを使用したロギング・フィーチャー
@WebService
@Features(features = "org.apache.cxf.feature.LoggingFeature")
public class CourseBuilderImpl implements CourseBuilder {
...
|
上記のコードでは、@Features アノテーションを使用して LoggingFeature クラスを指定し、サーバー・サイドでロギングを実行しています。
インターセプター・アノテーションやフィーチャー・アノテーションを使いたくない場合には、単純に @Logging アノテーションを使用してメッセージ・ロギングを実行することができます。以下のコードを使用すると、ロギングをさらに簡単に実行できるようになります。
リスト 8. @Logging アノテーション
@WebService
@Logging
public class CourseBuilderImpl implements CourseBuilder {
...
|
CXF では、Spring ベースの Bean 構成ファイルを使用して Web サービスを公開することもできます。Spring 構成ファイルを使用することによる当然のメリットとして、サービス Bean にフィーチャーとインターセプターを動的に追加することができ、コードを再コンパイルする必要がありません。私が以前に寄稿した、Apache CXF と Spring を使用した Web サービスの開発に関する記事を読むことをお勧めします。その記事では、Spring 構成ファイルを使用して Web サービスを作成し、最終的にその Web サービスを公開する手順を説明しています。
以下のコードは CourseBuilderImpl Bean を JAX-WS エンドポイントとして定義する構成ファイルを示しています。
リスト 9. CourseBuilderImpl サービス Bean を JAX-WS エンドポイントとして定義する
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:endpoint id="courseBuilder" implementor="demo.cxf.logging.CourseBuilderImpl" address="/CourseBuilder" /> </beans> |
<jaxws:endpoint> 要素を使用することで、CourseBuilderImpl サービス Bean を JAX-WS エンドポイントとして定義しています。エンドポイントの URL
はWeb コンテンツに対する相対 URL です (これは http トランスポートとして CXFServlet を使用している場合には当然です)。ここで、ロギング・インターセプターを使用するためには、上記のコードを以下のように変更する必要があります。
リスト 10. ロギング・インターセプターを構成する
<beans>
...
<bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<jaxws:endpoint
id="courseBuilder"
implementor="demo.cxf.logging.CourseBuilderImpl"
address="/CourseBuilder" >
<jaxws:inInterceptors>
<ref bean="logIn"/>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<ref bean="logOut"/>
</jaxws:outInterceptors>
</jaxws:endpoint>
</beans>
|
変更された上記のコードには、2 つのインターセプター Bean、つまり LoggingInInterceptor と
LoggingOutInterceptor が追加されています。これらの Bean の参照が、それぞれ <jaxws-inInterceptors> 要素と <jaxws-outInterceptors> 要素を使用して CourseBuilderImpl サービス Bean に渡されています。こうすることで、必ず受信サービス・メッセージと送信サービス・メッセージの両方のロギングが実行されます。
同様に、Spring を利用してロギング・フィーチャーを構成することもできます。以下のコードはロギング・フィーチャーを示しています。
リスト 11. ロギング・フィーチャーを構成する
<beans>
...
<jaxws:endpoint
id="courseBuilder"
implementor="demo.cxf.logging.CourseBuilderImpl"
address="/CourseBuilder" >
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature"/>
</jaxws:features>
</jaxws:endpoint>
</beans>
|
上記のコードを見るとわかるように、<jaxws:features> 要素を使用してロギング・フィーチャーを指定しています。
以上の内容を要約すると、この記事ではインターセプターやフィーチャーなど、CXF のネイティブ機能を利用してサービス・メッセージのロギングを実行する方法を詳しく探りました。アノテーションを使用することで、また Spring ベースの Bean 構成を使用することで、プログラムでメッセージ・ロギングを実行することができます。Apache CXF フレームワークは、Log4j や SLF4J などのロギング・フレームワークと統合することができ、Web サービス・ランタイムのためのさまざまなデバッグ・ツールもサポートしています。CXF を使用したロギングやデバッグについての詳細は、Apache CXF の「Debugging and Logging」を参照してください。
- 「Apache
CXF と Aegis を使用した Web サービスの開発: CXF と Aegis のデータ・バインディングを使用した Web サービスの開発方法を学ぶ」
- 「Spring、Apache CXF
を使用した POJO Web サービスの設計と実装: 第 1 回 CXF と Spring を使った Web サービス作成の概要」
- 「Spring、Apache
CXF を使用した POJO Web サービスの設計と実装: 第 2 回 RESTful な Web サービスを作成する」
- さまざまな IBM 製品や IT 業界のトピックに焦点を絞った developerWorks
の Technical events and webcasts で最新情報を入手してください。

Rajeev Hathi は J2EE プラットフォームに関するソフトウェア・コンサルタントです。彼はアーキテクチャーの設計、J2EE ベースのアプリケーションの設計や開発に専門的な関心を持っており、Java 技術と J2EE 技術 (コア Java、Web、EJB、アーキテクト) で SUN 認定を取得しています。また、IBM の developerWorks ポータルに何本かの技術記事を寄稿しているとともに、『Apache CXF Web Service Development』の共著者でもあります。彼の趣味は音楽鑑賞とスポーツ観戦です。彼の公式な Web サイトは技術ブログのサイト、http://www.rajeevhathi.comです。