■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2009年08月02日

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

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


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


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

では、前回読者への課題にしていた作業の解答例を下に提示します。(あくまで例
ですから、この通りにしなければならない訳ではありません。)


まず、jp.co.flsi.lecture.webservice.hotelパッケージの中に次のようなクラス
(MailSender)を作成しましょう。

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

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.apache.log4j.Logger;

public class MailSender {

   private static final long serialVersionUID = 1L;
   private static Logger logger = Logger.getLogger(MailSender.class);
   private static MailSender instance = new MailSender();
   private Properties props = new Properties();
  
   private MailSender() {
      InputStream inputStream = getClass().getResourceAsStream("/runmode.properties");
      if(inputStream != null) {
         try {
            props.load(inputStream);
         } catch (IOException e) {
            logger.error(e, e);
         }
      }
      logger.info("インスタンスを生成しました。 ...............");
   }
  
   public static MailSender getInstance() {
      return instance;
   }
  
   public void sendMessage(String subject, String text) {
      String smtpHost = props.getProperty("mail.smtp.host");
      String userid = props.getProperty("userid");
      String password = props.getProperty("password");
      String from = props.getProperty("from");
      String recipient = props.getProperty("to");
      Session session = Session.getInstance(props, null);
      try {
         MimeMessage message = new MimeMessage(session);
         message.setFrom(new InternetAddress(from)); // 送信者メール・アドレス
         InternetAddress[] to = { new InternetAddress(recipient) }; // 宛先メール・アドレス(配列で複数指定可)
         message.setRecipients(Message.RecipientType.TO, to);
         message.setSubject(subject); // メールのサブジェクト(件名)
         message.setText(text); // メールの本文
         Transport transport = session.getTransport("smtp");
         transport.connect(smtpHost, userid, password); // host, userid, password
         transport.sendMessage(message, to);         
      } catch (MessagingException e) {
         logger.error(e, e);
      }
   }
}
--------------------------------------------------------

このクラスはシングルトン(Singleton)になっていますね。シングルトンにすること
によって、プロパティー・ファイルを1回だけしか読み込まないようになっていますね。
(シングルトンが何だったか忘れた人はvol.145を復習してください。)
これによって、同じファイルを何度も読み込むような無駄をなくしています。

なお、読み込むプロパティー・ファイルの名前としては、vol.144のときに同じ
runmode.properties
を使っています。


次に、このMailSenderクラスで電子メールの送信を行うように、HotelSoapBindingImplを
書き換えましょう。下記のように書き換えてみてください。

--------------------------------------------------------
/**
 * 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.rmi.RemoteException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Vector;

import jp.co.flsi.lecture.webservice.hotel.db.BookingDbManager;
import jp.co.flsi.lecture.webservice.hotel.db.HotelDbException;
import jp.co.flsi.lecture.webservice.hotel.db.RoomDbManager;

import org.apache.log4j.Logger;

public class HotelSoapBindingImpl implements Hotel{

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

   public RoomInfo[] findRooms(StayInfoInput stayInfo) throws RemoteException {
      logger.info("Start ...............");
      Vector<RoomInfo> roomInfoVector = null;
      RoomDbManager roomDbManager = new RoomDbManager();

      try {
         String startDate = stayInfo.getStartDate();
         if (startDate.length() != 8) {
            logger.info("Invalid parameter: startDate(= " + startDate
                  + ") format not correct: must be 8 letters");
            throw new RemoteException("Invalid parameter: startDate(= " + startDate
                  + ") is invalid: must be 8 letters");
         }
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
         GregorianCalendar stayDate = new GregorianCalendar();
         stayDate.setTime(dateFormat.parse(startDate));
         if (stayDate.get(Calendar.YEAR) != Integer.parseInt(startDate.substring(0, 4)) ||
               (stayDate.get(Calendar.MONTH) + 1) != Integer.parseInt(startDate.substring(4, 6)) ||
               stayDate.get(Calendar.DAY_OF_MONTH) != Integer.parseInt(startDate.substring(6))) {
            logger.info("Invalid parameter: startDate(= " + startDate
                  + ") is not correct: impossible date");
            throw new RemoteException("Invalid parameter: startDate(= " + startDate
                  + ") is not correct: impossible date");
         }
         int numOfNights = stayInfo.getNumOfNights();
         int numOfLodgers = stayInfo.getNumOfLodgers();
         if (numOfNights < 1 || numOfLodgers < 1) {
            logger.info("Invalid parameter: numOfNights (" + numOfNights + ") or numOfLodgers ("
                  + numOfLodgers + ") is invalid.");
            throw new RemoteException("Invalid parameter: numOfNights (" + numOfNights
                  + ") or numOfLodgers (" + numOfLodgers + ") is invalid.");
         }

         roomDbManager.connect();
         roomInfoVector = roomDbManager.getData(numOfLodgers, stayInfo.getMinRatePerNight(),
               stayInfo.getMaxRatePerNight());
         int roomInfoSize = roomInfoVector.size();
         if (roomInfoSize > 0) {
            for (int roomIndex = roomInfoSize - 1; roomIndex > -1; roomIndex--) {
               RoomInfo roomInfo = roomInfoVector.get(roomIndex);
               stayDate.setTime(dateFormat.parse(startDate));  // 宿泊日の初日にリセット
               int roomNum = roomInfo.getRoomNum();
               for (int i = 0; i < numOfNights; i++) {
                  if (roomDbManager.isBooked(roomNum, stayDate)) {
                     roomInfoVector.remove(roomIndex);
                     break;
                  }
                  stayDate.add(Calendar.DAY_OF_MONTH, 1);
               }
            }
         }
      } catch (HotelDbException e) {
         logger.error(e, e);
          MailSender mailSender = MailSender.getInstance();
          mailSender.sendMessage("[Emergency] Hotel DB Exception!!!", "Hotel DB Exception occurred. Please check logs!\n");
      } catch (ParseException e) {
         logger.info(e);
         throw new RemoteException("ParseException occured (startDate format not correct)", e);
      }
      catch (RemoteException e) {
         logger.info(e);
         throw e;
      }
      catch (Throwable e) {
         logger.error(e, e);
      }
      finally {
         try {
            roomDbManager.disconnect();
         }
         catch (Exception e) {
            logger.info("Disconnect failed or there is no connection.");
         }
         logger.info("End ...............");
      }

      return roomInfoVector.toArray(new RoomInfo[roomInfoVector.size()]);
   }

   public boolean reserveRoom(RoomReserveInfo roomReserve) throws RemoteException {
      logger.info("Start ...............");
      BookingDbManager bookingDbManager = new BookingDbManager();

      try {
         String startDate = roomReserve.getStartDate();
         if (startDate.length() != 8) {
            logger.info("Invalid parameter: startDate(= " + startDate
                  + ") format not correct: must be 8 letters");
            throw new RemoteException("Invalid parameter: startDate(= " + startDate
                  + ") is invalid: must be 8 letters");
         }
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
         GregorianCalendar startStayDate = new GregorianCalendar();
         startStayDate.setTime(dateFormat.parse(startDate));
         if (startStayDate.get(Calendar.YEAR) != Integer.parseInt(startDate.substring(0, 4)) ||
               (startStayDate.get(Calendar.MONTH) + 1) != Integer.parseInt(startDate.substring(4, 6)) ||
               startStayDate.get(Calendar.DAY_OF_MONTH) != Integer.parseInt(startDate.substring(6))) {
            logger.info("Invalid parameter: startDate(= " + startDate
                  + ") is not correct: impossible date");
            throw new RemoteException("Invalid parameter: startDate(= " + startDate
                  + ") is not correct: impossible date");
         }
         int numOfNights = roomReserve.getNumOfNights();
         int numOfLodgers = roomReserve.getNumOfLodgers();
         if (numOfNights < 1 || numOfLodgers < 1) {
            logger.info("Invalid parameter: numOfNights (" + numOfNights + ") or numOfLodgers ("
                  + numOfLodgers + ") is invalid.");
            throw new RemoteException("Invalid parameter: numOfNights (" + numOfNights
                  + ") or numOfLodgers (" + numOfLodgers + ") is invalid.");
         }
         bookingDbManager.connect();
         bookingDbManager.insertData(roomReserve.getRoomNum(), roomReserve.getName(),
               roomReserve.getAddress(), roomReserve.getTelNo(),
               startStayDate, numOfNights, numOfLodgers);
        
      } catch (HotelDbException e) {
         logger.error(e, e);
          MailSender mailSender = MailSender.getInstance();
          mailSender.sendMessage("[Emergency] Hotel DB Exception!!!", "Hotel DB Exception occurred. Please check logs!\n");
         return false;
      } catch (ParseException e) {
         logger.info(e);
         throw new RemoteException("ParseException occured (startDate format not correct)", e);
      }
      catch (RemoteException e) {
         logger.info(e);
         throw e;
      }
      catch (Throwable e) {
         logger.error(e, e);
         return false;
      }
      finally {
         try {
            bookingDbManager.disconnect();
         }
         catch (Exception e) {
            logger.info("Disconnect failed or there is no connection.");
         }
         logger.info("End ...............");
      }
      return true;
   }

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


続いて、プロパティー・ファイルのほうを編集しましょう。
vol.144と同じく、C:\Tomcat6.0\webapps\axis\WEB-INF\classesフォルダーの中に、
下記のような内容のファイルを作成し、runmode.propertiesというファイル名
にして下さい。(vol.144で作成したときのファイルが残っていれば、その中身を編集
するだけでいいです。)

--------------------------------------------------------
mail.smtp.host=smtp.sirimasen.co.jp
mail.smtp.port=25
mail.smtp.auth=true
userid=sirimasenuserid
password=sirimasenpassword
from=soushinsha@sirimasen.co.jp
to=jushinsha@wakarimasen.co.jp
--------------------------------------------------------

もちろん上記の値をそのまま指定するのではなく、実際使用可能な値を設定して
ください。


あとは、例によってAntでデプロイを行っておけば完成です。



では、以上でWebサービス側の開発はひとまず終わったということにして、
このWebサービスを本番用のコンピューターにデプロイするという作業を行っ
てみましょう。(もちろん本当に本番に移行する訳ではありませんが、そう
いう場面を想定して作業をしてみましょう。)

Javaのサーバー・システムを本番で稼動させるコンピューターのOSはUNIXの場合が
多いですが、最近ではLinuxを使用するケースも増えてきています。そして、Linuxは
UNIXと操作性が同じで、かつ無料(オープン・ソース)で普通のPC(パソコンのこと)
にも簡単にインストールできるので、教材としても最適だと思います。
というわけで、当講座でもLinuxを使用することにします。
(LinuxはUNIXと操作性が同じなので、Linuxが使用できる人はUNIXも使用できます。)


Linuxには様々なディストリビューション(distribution = 配布パッケージ)があり
ますが、サーバー用としてはCentOS

http://www.centos.org/

をお勧めします。CentOSというのは簡単に言うとRed Hat Enterpise Linux(有料)の
無料版のようなもので、有料版のRed Hat Enterpise Linuxと内容的にはほぼ同等です。
したがって、実際に企業で運用されているサーバーに近いシステムを組めます。

なお、Linuxのインストール方法から操作方法まで、すべてこのメールマガジンで説明
しようかと思ったのですが、それでは余りにも執筆に手がかかりすぎるし、Java以外の
説明にあんまり時間を使い過ぎると、当メールマガジンの本題から逸脱してしまうので、
やめることにしました。
代わりに、

http://www.lpi.or.jp/linuxservertext/

から「Linuxサーバー構築標準教科書」(ダウンロード無料)などをダウンロードして
読むとよいでしょう。(上記Webページの下のほうにDownloadのコーナー(オレンジ色
の枠で囲まれている)があります。)
(あるいは、Linuxのインストール方法は、他に
http://www.centos.org/
のホームページの中にもInstallationマニュアルがあります。)

当メールマガジンではこれを前提として、話を進めて行きたいと思います。


では、さっそくですが、古くなったPCなど、余っている不要なPCがあれば、そこにLinux
をインストールしておいてください。ただし、開発用のPCとLANでつながっている必要
があります。最近では、中古の不要なPCが世に満ち溢れているそうですから、中古店や
インターネット上のオークション・サイトなどでも安く売られています。(逆に高いと
誰も買わない。)数千円くらいでもLinux用としては十分なPCが購入できますので、利用
してもよいでしょう。
Linux用のPCが手に入らない人は、メールマガジンを読むだけで我慢してください。


(次回に続く)


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



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