■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2009年03月15日

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

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


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


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


では、今回は、Propertiesクラスを使ってプロパティー・ファイルを
を読み出し、プロパティーの値を取り出す方法を説明します。


まず、プロパティー・ファイルを読み出すためには、Propertiesクラスの
load()メソッドを使用します。このメソッドの引数には、InputStream型
のオブジェクトが指定できますので、例えば

Properties properties = new Properties();
properties.load(new FileInputStream("nantoka.properties"));

のようにして、プロパティー・ファイルを指定することができます。
しかし、このときファイルの置き場所が問題になります。

現在使っているAxisはTomcatのアプリケーションとして実行されますが、
Tomcatのアプリケーションでは、プロパティー・ファイルはclassesディレ
クトリーに置くのが標準になっています。ところが、このclassesディレク
トリー(現在の絶対パスはC:\Tomcat6.0\webapps\axis\WEB-INF\classesに
なっている)の絶対パスはTomcatのインストールの仕方によって異なります
から、Webサービスのプログラムの中で明記する訳にはいきません。

しかし、幸いにもclassesディレクトリーはこのWebサービス(Tomcatのアプ
リケーション)を起動する際にクラス・ローダーがクラスを探してくる場所
(いわゆるクラスパス)なので、クラス・ローダーが認識しています。
そのため、例えば次のようにして、クラス・ローダーにプロパティー・ファ
イルを探させて、Propertiesクラスのload()メソッドで読み出すということ
が可能になります。

InputStream inputStream = getClass().getClassLoader().getResourceAsStream("nantoka.properties"); 
properties.load(inputStream); 

ここで、getClass()はすべてのオブジェクトのスーパークラスであるObjectクラスの
メソッドで、現在のオブジェクトのクラスを表すClassクラスのインスタンスを返し
ます。(このClassという名前のクラスは、クラスを管理するクラスで一般には
「メタ・クラス」と呼ばれるものです。Classというクラスは既にvol.023でも
出てきました。このClassというクラスのインスタンスは各クラスを表します。
たとえば、このインスタンスのgetName()メソッドを実行すると、そのオブジェクト
のクラス名を返してくれます。)
ここでは、そのClassクラスのインスタンスのgetClassLoader()メソッドを実行する
ことによって、そのクラスをロードしたクラス・ローダーを呼び出しています。
そして、そのクラス・ローダーのgetResourceAsStream()メソッドを呼び出すこと
によって、その引数に指定したファイルをクラスパスから探させて、そのファイルを
読み込むためのInputStreamオブジェクトを作成させています。
そうすれば、あとはPropertiesクラスのload()メソッドの引数にそのInputStreamオブ
ジェクトを指定してやれば、そのプロパティー・ファイルを読み込める訳です。


では、この仕組みを使って、"runmode.properties"というファイル名のプロパティー・ファイル
を読み込むように、HotelSoapBindingImplクラスを編集してみましょう。
Eclipseを起動して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.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
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>();

      InputStream inputStream = getClass().getClassLoader().getResourceAsStream("runmode.properties"); 
      if(inputStream != null) {
         Properties properties = new Properties(); 
         try {
            properties.load(inputStream);
         } catch (IOException e1) {
            logger.error(e1);
         }
         String testValue = properties.getProperty("test");
         if (testValue != null && testValue.equals("yes")) {
            RoomInfo roomInfo0 = new RoomInfo();
            roomInfo0.setRoomNum(100);
            roomInfo0.setCapacity(2);
            roomInfo0.setRatePerNight(20000);
            roomInfo0.setRoomType("SINGLE");
            roomInfo0.setWebBrowsable(true);
            roomInfoVector.add(roomInfo0);
            return roomInfoVector.toArray(new RoomInfo[roomInfoVector.size()]);
         }
      }

      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);
                     logger.debug("roomInfo.setWebBrowsable(true);の行が実行されました。");
                  }
                  else {
                     roomInfo.setWebBrowsable(false);
                     logger.debug("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;
   }

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

ここで、getProperty()というメソッドは、プロパティーの値を取り出すメソッドで、
引数にはプロパティーの名前(通常、「キー」と呼ぶ)を指定します。

ここでは、"runmode.properties"というプロパティー・ファイルの中に

test=yes

という指定(つまり、"test"というキーに対して"yes"という値が指定されている場合)
があった場合には、データベースにはアクセスせずに、テスト用のデータを返すように
findRooms()メソッドを編集しています。


では、C:\Tomcat6.0\webapps\axis\WEB-INF\classesフォルダーの中に、
下記のような内容のファイルを作成し、runmode.propertiesというファイル名
にして下さい。

--------------------------------------------------------
secure=yes
test=yes
--------------------------------------------------------

ここで実際に読み込みたいプロパティーは2行目なんですが、"test"というキーが
ちゃんと読まれることを確認するために、1行目には別のキーを指定しています。



では、これらのファイルの編集が終わったら、保管したあと、前回と同じく
再度、デプロイを行い、再度HotelClientを実行してみて下さい。

今度は、上でHotelSoapBindingImpl.javaを編集した通り、テスト用のデータが
返され、コンソールに

==============================================
Room number : 100
Room capacity : 2
Rate per night : 20000
Room type : SINGLE
Web browsable : true
==============================================

という結果が返ってきますね。

これで、ちゃんとプロパティー・ファイルが読み込まれたことがわかります。



(次回に続く)


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



================================================
◆ 02.演習問題
================================================

今回はHotelSoapBindingImpl.javaのプログラムを編集して、findRooms()メソッド
がデータベースにはアクセスせずに、テスト用のデータを返すようにしましたが、
このテスト用のデータは返さずに、前回と同じようにデータベースのデータを
返すようにするには、runmode.propertiesファイルをどう編集すればいいで
しょうか。実際にrunmode.propertiesファイルを編集して試してみて下さい。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      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. 不許無断複製