■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2009年03月01日

    Java総合講座 - 初心者から達人へのパスポート
                  vol.142

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


[このメールマガジンは、画面を最大化して見てください。]


========================================================
◆ 01.SOAPのアプリケーション(Webサービス)
========================================================


さて、前回、最後のビルド・ファイルの編集のときに、wsdl2javaのターゲットの
実行とデプロイの実行を一まとめに行わずに、分けて行うようにしましたが、
その理由をここで述べておきましょう。。


通常は、開発に使うコンピューター(こちらは公開されないコンピューター)と
デプロイを行うコンピューター(こちらは通常、一般公開されるコンピューター
である)は異なるので、同じコンピューターでwsdl2javaのターゲットの実行と
デプロイの実行を連続して行うことはできません。(ネットワークを経由して
デプロイを行う方法によって、これらを連続して行うことも可能ですが、セキュリ
ティー上、好ましくないので、通常はネットワーク経由のデプロイは行いません。)
つまり、wsdl2javaのターゲットの実行は開発環境のコンピューターで行い、
デプロイの実行は一般公開用のコンピューターで行いますので、これらのター
ゲットは別々に実行するようにしておくわけです。

実際に、別のPC(LinuxをインストールしたPC)にデプロイを行う手順を、後ほど
別の機会に説明いたします。



さて、これからWebサービスの実装を行いますが、そのときにLog4jという
ツールを使いますので、これについてここでちょっと説明しておきましょう。

Log4jについては、vol.023やvol.129でもちょっとふれましたが、
ログを書き出すためのオープン・ソースのAPIです。

ログ(log)とは、プログラムの活動状況(いつ、どのプログラムで、何が
起こったか、という事象)を記録したファイルで、特にプログラムの実行時に
何か問題が発生したときや、テスト時に何らかのバグが発覚したときなどに、
詳しい状況を確認するために使われます。

したがって、ログにはプログラムの動作時の情報ができるだけ詳しく書かれて
いたほうがいいのですが、かといって、ログ出力のためにコンピューターに
大きな負荷がかかってしまっては本末転倒になってしまいます。

そのためにLog4jが開発されました。

Log4jはApacheソフトウエア・ファウンデーションが提供するオープン・ソース
の一つですが、このソフトはコンピューターにかかる負荷が極めて小さくて
済むように作られているので、ログ出力のツールとしてほとんど標準的に
使われるようになってきました。

しかも、Axisには予めLog4jが組み込まれています。(Tomcatのaxis/WEB-INF/lib
ディレクトリーにlog4j-1.2.8.jarというファイル名でLog4jのJARファイルが
はいっています。)


というわけで、これからこのLog4jの使い方を簡単に説明しておきたいと
思います。


それでは、Eclipseを起動して、JStudySOAPプロジェクトの
jp.co.flsi.lecture.webservice.hotelパッケージ
のHotelSoapBindingImpl.javaをLog4jでログ出力を行うように
編集してみましょう。

なお、HotelSoapBindingImpl.javaなどのWSDLから自動生成したソース・コード
はUTF-8でエンコーディングされていることを思い出しましょう。
Eclipseの標準ではデフォルトのエンコーディングがShift-JIS(正確に言うと
MS932)になっているので、このままで編集するわけにはいきません。
(実際、先頭のコメントの「このファイルはWSDLから自動生成されました」などの
文字列が文字バケしていますね。)

というわけで、予めエンコーディングをUTF-8に変更しておきましょう。やり方は、
vol.128でもお話したように、

[方法A]
(1) パッケージ・エクスプローラーでプロジェクトまたはパッケージまたはクラス
などを右クリックし、「プロパティー」を選択する。
(2) 「プロパティー」ウインドウで「情報」を選択し、右側の
「テキスト・ファイル・エンコード」の中で「その他」を選択する。
(3) 「その他」の右側の逆三角形のボタンをクリックして「UTF-8」(スクロールして
一番下にある)を選択し、「OK」ボタンをクリックする。

でもいいし、あるいは、現在編集中のファイルのエンコーディングを変更したい
場合は、ファイル(エディター)の中にカーソルがはいっている状態で

[方法B]
(1) メニュー・バーの「編集」→「エンコードの設定」を選択する。
(2) 「テキスト・ファイル・エンコード」の中で「その他」を選択する。
(3) 「その他」の右側の逆三角形のボタンをクリックして「UTF-8」(スクロールして
一番下にある)を選択し、「OK」ボタンをクリックする。

と操作することもできます。
基本的には、このパッケージの中のファイルはすべてUTF-8なので、[方法A]の
やり方で、パッケージごとUTF-8に設定しておきましょう。


では、Log4jによるログ出力のプログラミングですが、
HotelSoapBindingImpl.javaを下記のように編集してみて下さい。

--------------------------------------------------------
/**
 * HotelSoapBindingImpl.java
 *
 * このファイルはWSDLから自動生成されました / [en]-(This file was auto-generated from WSDL)
 * Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java生成器によって / [en]-(by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.)
 */

package jp.co.flsi.lecture.webservice.hotel;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Vector;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.apache.log4j.Logger;

public class HotelSoapBindingImpl implements jp.co.flsi.lecture.webservice.hotel.Hotel{
  
   Logger  logger = Logger.getLogger(HotelSoapBindingImpl.class);
  
   public jp.co.flsi.lecture.webservice.hotel.RoomInfo[] findRooms(jp.co.flsi.lecture.webservice.hotel.StayInfoInput stayInfo) throws java.rmi.RemoteException {
      logger.info("HotelSoapBindingImpl.findRooms()を開始します。 ...............");
      Vector<RoomInfo> roomInfoVector = new Vector<RoomInfo>();
      try{
         Context initCtx = new InitialContext();
         if(initCtx == null) throw new Exception("Error: InitialContext could not be generated!");
         DataSource ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/HOTELDB");
         if (ds != null) {
            Connection conn = ds.getConnection();
            if(conn != null)  {
               Statement selectSql = conn.createStatement();
               ResultSet rs = selectSql.executeQuery("SELECT * FROM ROOMINFO");
               while (rs.next()) {
                  RoomInfo roomInfo = new RoomInfo();
                  roomInfo.setRoomNum(rs.getInt("ROOMNUM"));
                  logger.info("ROOMNUM = " + rs.getInt("ROOMNUM"));
                  roomInfo.setCapacity(rs.getInt("CAPACITY"));
                  roomInfo.setRatePerNight(rs.getInt("RATE"));
                  roomInfo.setRoomType(rs.getString("TYPE"));
                  if ("Y".equals(rs.getString("WEB"))) {
                     roomInfo.setWebBrowsable(true);
                  }
                  else {
                     roomInfo.setWebBrowsable(false);
                  }
                  roomInfoVector.add(roomInfo);
               }
               selectSql.close();
               conn.close();
            }
         }
      }
      catch(Exception e) {
         logger.error(e);
      }
      finally {
         logger.info("HotelSoapBindingImpl.findRooms()を終了します。 ...............");
      }
      return roomInfoVector.toArray(new RoomInfo[roomInfoVector.size()]);
   }

   public boolean reserveRoom(jp.co.flsi.lecture.webservice.hotel.RoomReserveInfo roomReserve) throws java.rmi.RemoteException {
      return false;
   }

}
--------------------------------------------------------

ここでは前回のソースに対して、

import org.apache.log4j.Logger;



Logger  logger = Logger.getLogger(HotelSoapBindingImpl.class);



logger.info("HotelSoapBindingImpl.findRooms()を開始します。 ...............");



logger.info("ROOMNUM = " + rs.getInt("ROOMNUM"));



finally {
   logger.info("HotelSoapBindingImpl.findRooms()を終了します。 ...............");
}

が追加され、

e.printStackTrace();



logger.error(e);

に書き換えられていますね。

このうち、LoggerというクラスはLog4jの中でログ出力を担当するクラスであり、
getLogger()メソッドを実行すると、その引数に指定した項目に対するインスタンス
を生成してくれます。なお、このインスタンスは、引数に指定した名前ごとに生成
され、既に同じ名前に対するインスタンスが存在する場合は、getLogger()メソッド
はその既存のインスタンスを返すことになります。
(ここで引数に指定する名前は、文字列(例えば、"HotelService"など)を指定する
こともできますが、上記のHotelSoapBindingImpl.classのように「クラス名.class」
を指定すると、そのクラス名を指定したことになります。(「クラス名.class」は
そのクラスのClassオブジェクトを参照しますが、getLogger()メソッドはその
ClassオブジェクトのgetName()を実行してクラス名を取り出します。))

あとは、このLoggerのインスタンス(ここではloggerという変数名にしている)に
対して、ログ出力を行うように命令すればいいだけです。
ログ出力の命令としては、上のソース・コードでは、info()とerror()というメソッド
が呼び出されていますが、error()はエラー時の情報を出力するためのもので、
info()はエラー時ではなく単なる情報として出力するためのものです。
それぞれ、引数に指定した文字列がログ出力されることになりますが、error(e)
のようにExceptionオブジェクトを引数に指定した場合は、Exceptionオブジェクトに
設定されたメッセージがログ出力されます。
他に、warn()、fatal()、log()、debug()というメソッドもあり、詳しくは次回以降に
お話します。
なお、これらがすべてログ出力されるとは限らず、ログの「レベル(Level)」の設定
によって、実際に出力するかどうかが決まりますが、これも次回以降に詳しくお話いた
します。

あと、

finally {
}

というブロックは、例外(Exception)が発生しようとしなかろうと(catch()のブロッ
クが実行されようとされなかろうと)、このメソッドが終了するときに実行されるブ
ロックです。つまり、finallyブロックに入れた行は、メソッドの最後に必ず実行され
ますので、ここにメソッドの終了を意味するログ出力を入れておけば、たとえ例外が
発生したときでも確実にメソッドの終了がログに記録されることになります。



では、以上のソース・コードの編集が終わったら、保管し、続いて再度デプロイを
行っておきましょう。

つまり、前回と同じく、まず、Tomcatを起動しておき、

(1) JStudySOAP配下のbuild.xmlを右クリックし、「実行」→「3 Antビルド...」を
選択します。

(2) deployにチェック・マークを入れ、他のターゲットはチェック・マークを外した
状態で、「実行」ボタンをクリックします。

(3) Antが実行され、コンソールにメッセージが表示されます。最終的に

BUILD SUCCESSFUL
Total time: 5 seconds

のようなメッセージが表示されればデプロイが完了です。
(ただし、Total timeの数字は環境によって異なります。)


デプロイが完了しましたら、前回と同じくHotelClientを実行してみて下さい。

ログ出力が行われているはずなので、ログを見てみましょう。

Tomcatのlogsディレクトリー、つまり

C:\Tomcat6.0\logs

の中に、

stdout_YYYYMMDD.log
(ここでYYYYMMDDは年月日を表す数字)

というファイルがありますので、これをNoEditorなどのテキスト・エディターで
開いて見て下さい。

先ほどソース・コードの中に記述したログ出力が行われていることがわかりますね。
具体的には、

--------------------------------------------------------
- HotelSoapBindingImpl.findRooms()を開始します。 ...............
- ROOMNUM = 101
- ROOMNUM = 102
- ROOMNUM = 103
- ROOMNUM = 105
- ROOMNUM = 106
- ROOMNUM = 107
- ROOMNUM = 108
- ROOMNUM = 201
- ROOMNUM = 202
- ROOMNUM = 203
- ROOMNUM = 205
- ROOMNUM = 206
- ROOMNUM = 207
- ROOMNUM = 208
- ROOMNUM = 301
- ROOMNUM = 302
- ROOMNUM = 303
- ROOMNUM = 305
- ROOMNUM = 306
- ROOMNUM = 307
- ROOMNUM = 308
- HotelSoapBindingImpl.findRooms()を終了します。 ...............
--------------------------------------------------------

という出力内容が見つかるはずです。


(次回に続く)


では、今日はここまでにします。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2009 Future Lifestyle Inc. 不許無断複製