« 2008年1月 | トップページ | 2008年3月 »

2008年2月

JavaMail:メール送信でOP25B対応

【概要】
昨今のスパムメール対策により,Javaプログラムからのメール送信が困難な場合がでてきています。送信先がLAN内だったり,LAN内のメールサーバ(MTA)をリレーしたり,ISPが提供するメールサーバをリレーしてメール送信するなら問題ありませんが,JavaプログラムからISPのユーザ回線を経由してインターネットの向こう側に設置しているメールサーバでメールをリレーしようとすると,最近各ISPが導入を進めているOutbound Port 25 Blocking(OP25B)によりメール送信が阻止されてしまうことがあります。
Outbound Port 25 Blockingとは,一般ユーザのパソコンから送信用メールサーバをリレーせずに直接送信先のメールサーバへメールを送りつけるのを禁止するもので,ISPのユーザ回線から外部の25番ポート(SMTP)へ接続するのを阻止することで実現しています。これにより25番ポートからインターネットへメール送信できるのはISPのメールサーバや固定IPを取得したホストに限られますが,メールをリレーする送信用メールサーバがISPの外側にいる場合にも接続が阻止される弊害が出ています。
この対策としては,ISPの外側にいるメールサーバがメール送信のリレーを受け付けるときは25番以外のポート番号を使用すればよいということになります。この代替ポートとして「サブミッションポート」と呼ばれる587番ポートを使うようメールサーバを設定することができます。このとき587番ポートが正規のアカウントによるメール送信のみに使われるように,587番ポートはSASL認証必須に設定します。メールサーバ側のサブミッションポート対応についてはこちらの記事の後半にて,Mac OS X Serverで稼動するPostfixの設定方法を解説しています。

【JavaMailによる実装例】
この記事では,JavaプログラムからJavaMailを使ってメール送信するときに,メールサーバに25番ではなく587番ポートに接続して,SASL認証を行った上でメール送信するコードを例示します。なお,JavaMailを使用するには,事前にJavaMailとJAFをダウンロードして,クラスパスで指定されているディレクトリにJavaMailの「mail.jar」とJAFの「activation.jar」をインストールしておく必要があります。(JAFはJava SE 6に含まれるようになったので,Java SE 6ではJAFのインストールは不要です。)
JavaMailダウンロード:[JavaMail][JAF]
クラスパスの設定:[概要][Windows][Solaris][Mac OS X]
下記のコードではSASLの認証方法として「AUTH LOGIN」で認証できることを確認しています。認証方法「CRAM-MD5」については,JavaMailではSMTPで未サポートのようです(出典)。

下記のコードは25番ポートへ認証なしにメールを送信する場合と以下の点が異なります。
1)接続先SMTPサーバのポート番号を587番に指定:
→プロパティ「mail.smtp.port」を「587」に設定。

2)SASL認証(SMTP Auth)を試みるよう指定:
→プロパティ「mail.smtp.auth」を「true」に設定。

3)SASL認証で使用する認証情報クラスを用意する:
→Authenticatorクラスを継承し,getPasswordAuthenticationメソッドを実装したクラス(PassAuther)を用意する。

4)Session取得時に認証情報クラスインスタンスで初期化:
→Session.getDefaultInstance()メソッドの第二引数にPassAutherのインスタンスを渡す。

【WebObjectsでJavaMailを使う場合の注意】
WebObjectsアプリケーションではデフォルトで「Session」というクラスが作られるため,JavaMailのSessionクラスとクラス名のバッティングが起こります。そのためJavaMailのSessionクラスを指定する場合に「javax.mail.Session」とフルパスでクラス名を指定するなどの対応が必要です。

JavaMailを使って587番ポートからSASL認証してメール送信を行う実装例:

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
/**
 * SendSASLMail:メール送信クラス.
 */
public class SendSASLMail
{
  /**
   * PassAuther:認証情報クラス.
   */
  private class PassAuther extends Authenticator
  {
    private String mUserName;
    private String mPassword;
    //------------------------------------------------------------------
    /**
     * PassAutherクラスのコンストラクタ.
     * @param userName SASL認証で使うユーザ名.
     * @param passwd  同パスワード.
     */
    public PassAuther (
      String userName,
      String passwd)
    {
      super();
      mUserName = userName;
      mPassword = passwd;
    }
    //------------------------------------------------------------------
    /**
     * Authenticatorの派生クラスで必須のメソッド.
     */
    public PasswordAuthentication getPasswordAuthentication ()
    {
      return new PasswordAuthentication(mUserName, mPassword);
    }
  }

  private String mHostName;
  private String mUserName;
  private String mPassword;

  //------------------------------------------------------------------
  /**
   * SendSASLMailクラスのコンストラクタ.
   * @param host   送信用ホスト名.
   * @param userName SASL認証用ユーザ名.
   * @param passwd  SASL認証用パスワード.
   */
  public SendSASLMail (
    String host,
    String userName,
    String passwd)
  {
    mHostName = host;
    mUserName = userName;
    mPassword = passwd;
  }

  //------------------------------------------------------------------
  /**
   * メール送信実行メソッド.
   * @param from   差出人.
   * @param toList  宛先リスト.
   * @param ccList  CCリスト.
   * @param bccList BCCリスト.
   * @param subject Subject.
   * @param message メール本文.
   * @throws MessagingException
   * @throws AuthenticationFailedException
   * @throws SendFailedException
   */
  public void send (
    Address  from,
    Address[] toList,
    Address[] ccList,
    Address[] bccList,
    String   subject,
    String   message)
    throws MessagingException, AuthenticationFailedException, SendFailedException
  {
    if (from != null && toList != null && 0 < toList.length) {
      Properties props = new Properties();
      props.setProperty("mail.transport.protocol", "smtp");
      props.setProperty("mail.smtp.host", mHostName);
      props.setProperty("mail.smtp.port", "587");
      props.setProperty("mail.host", mHostName);
      props.setProperty("mail.smtp.connectiontimeout", "60000");
      props.setProperty("mail.smtp.timeout", "60000");
      props.setProperty("mail.smtp.auth", "true");

      Authenticator auther = new PassAuther(mUserName, mPassword);
      Session session = Session.getDefaultInstance(props, auther);

      // session.setDebug(true); // デバッグ情報を表示する.
      MimeMessage mmsg = new MimeMessage(session);

      mmsg.setFrom(from);
      mmsg.setRecipients(Message.RecipientType.TO, toList);
      if (ccList != null && 0 < ccList.length) {
        mmsg.setRecipients(Message.RecipientType.CC, ccList);
      }
      if (bccList != null && 0 < bccList.length) {
        mmsg.setRecipients(Message.RecipientType.BCC, bccList);
      }
      if (subject != null && 0 < subject.length()) {
        mmsg.setSubject(subject, "iso-2022-jp");
      }
      mmsg.setText(message, "iso-2022-jp");
      mmsg.setSentDate(new Date());

      Transport.send(mmsg);
    }
  }

  //------------------------------------------------------------------
  /**
   * 動作確認用mainメソッド.
   * @param args
   */
  public static void main(String[] args)
  {
    SendSASLMail sender = new SendSASLMail("mail.example.com", "username", "password");
    try {
      Address from = new InternetAddress("address@example.com", "差出人", "iso-2022-jp");
      Address to = new InternetAddress("addr1@example.com", "宛先1(TO)", "iso-2022-jp");
      Address cc = new InternetAddress("addr2@example.com", "宛先2(CC)", "iso-2022-jp");

      Address[] toList = new Address[] {to};
      Address[] ccList = new Address[] {cc};

      String subject = "テストメール";
      String message = "JavaMailからのメールです。";

      sender.send(from, toList, ccList, null, subject, message);
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

※上記コードでは,整形のため全角スペースを使用している部分があります。
【著作権表記】上記コードを含む本ブログのプログラムコードは,私的利用可,商用利用可,改変しての利用可です。利用の際に作者に許諾を得る必要はありません。

■関連情報
ISPによるOP25B 実施状況((財)日本データ通信協会・迷惑メール相談センター)
メール送信サンプル:[JavaMail(SMTP)編(JavaでHelloWorld)][JavaMailでメール送信アプリを作る(@IT Java Tips)]
JavaMail完全解説
Sun:[JavaMail]
API Reference(javadoc):[JavaMail][J2EE 1.3.1]
ダウンロード:[JavaMail][JAF]
WebObjects:WOMailDeliveryで日本語メール送信

■関連書籍をAmazonで検索:[JavaMail][Java]
独習Java サーバサイド編 第2版 (kindle版)



にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。

| | トラックバック (0)

Java:ログインパスワードを暗号化する

Webアプリケーションなどでは,アクセス時にパスワードによるログイン認証を行う場合があります。
ここではその具体的な実装のうち,データベースやパスワードファイルに格納するログインパスワードの暗号化について述べてみたいと思います。

【概要】
複数のユーザが個別にユーザ名とパスワードを設定する場合,そのアカウント情報はデータベースなどに保存するようになると思います。
このときパスワードをそのまま保存してしまうと,パスワードはデータベースを閲覧できるすべての人に知られてしまいます。また,Base64変換や元に戻せる暗号にした場合でも,元に戻せる技術をもった人にパスワードを知られてしまう可能性があります。そのため,パスワードを保存する場合は不可逆暗号にするのが一般的かと思います。
不可逆暗号とは元に戻せない暗号です。不可逆暗号を使ってパスワード認証を行うには,暗号化したパスワードをデータベースにあらかじめ保存しておき,ユーザがログインした時にユーザが入力したパスワードを暗号化して,データベースに保存されている暗号化されたパスワードと同一になるかどうかで正しいパスワードか判断することができます。不可逆のメリットとしては,元に戻せないのでパスワードの漏洩が防げると同時に,データベースを閲覧できる人にパスワード窃盗の嫌疑がかかるのを防ぐことができます。デメリットとしては,元に戻せないのでユーザがパスワードを忘れてしまったらパスワードを登録し直すしか手がないことです。

パスワードだけを暗号化した場合,同じパスワードの人がいた場合に同じ暗号データがデータベースに登録されてしまい,データベースを閲覧した人に同じパスワードであることがわかってしまう可能性があります。この対策としては,(ユニークな)ユーザ名とパスワードを加えて暗号化すれば良いかと思います。

【Javaによる不可逆暗号の実装】
Javaにはメッセージダイジェストを作成するクラスがありますので,これを使って不可逆暗号を作ることができます。具体例として下記のようなコードになります。
なお,このコードではユーザ名がNULLであることを想定していません。なぜならユーザ名はアカウントを特定するユニークキーなので,必須であるべきだからです。ユーザがユーザ名を入力しなかった場合は,このメソッドを呼ぶ前にエラーではじくべきです。
※このコードでは,メッセージダイジェストをテキストに変換するために,当初Base64エンコードしていましたが,バイトごとの数値を文字列に変換して連結する実装に改めました(2015/02/16)

import java.security.*;
 
/**
* パスワードを不可逆暗号化する.
*/
public class PassDigest
{
  //------------------------------------------------------------------
  /**
   * ユーザ名とパスワードでメッセージダイジェストを作成し文字列化して返す.
   * @param userName ユーザ名.
   * @param password パスワード.
   * @return 生成したダイジェスト.
   * @throws NoSuchAlgorithmException Java実行環境にSHA-1が実装されていない.
   */
  public static String build (
    String userName,
    String password)
    throws NoSuchAlgorithmException
  {
    StringBuilder buff = new StringBuilder();
    if (password != null && !password.isEmpty()) {
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      md.update(userName.getBytes());
      md.update(password.getBytes());
      byte[] digest = md.digest();

      for (byte d : digest) {
        buff.append((int)d&0xFF);
      }
    }
    return buff.toString();
  }
}

最終更新日:2015/02/16
※上記コードでは,整形のため全角スペースを使用している部分があります。
【著作権表記】上記コードを含む本ブログのプログラムコードは,私的利用可,商用利用可,改変しての利用可です。利用の際に作者に許諾を得る必要はありません。

■関連情報
Sun:Java暗号化アーキテクチャ API の仕様およびリファレンス
クラスMessageDigest(Javadoc)

■関連書籍をAmazonで検索:[Java]
Javaで作って学ぶ暗号技術 - RSA,AES,SHAの基礎からSSLまで



にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。


ioPLAZA【グラフィック(内蔵)】ブックオフオンライン【PC・携帯共通】

| | トラックバック (0)

WebObjects:メモリ不足エラー対応

【問題】
WebObjectsで開発したWebアプリケーションが稼動中にメモリ不足でメモリ割り当てできなくなったとき,OutOfMemoryError例外が発生します。

【対応策】
WebObjectsで開発するWebアプリはJavaアプリケーションなので,対応策は基本的にJavaアプリケーションと同じです。

割り当てメモリと残メモリの調査
Webアプリケーションには,起動時にJava VMからヒープメモリが割り当てられます。Webアプリケーションは,実メモリサイズにかかわりなく割当メモリサイズ以上のメモリを使用することはできません。そのため,まずはWebアプリケーションがJavaVMから十分なサイズのメモリを割り当てられているかを確認しておく必要があります。
割り当てられたヒープメモリのサイズは以下のコードで調べることができます。このコードはたとえばmainメソッドの先頭に埋め込むと良いでしょう。

割り当てメモリサイズを表示するJavaプログラムコード
long total = Runtime.getRuntime().totalMemory();
System.out.println("Total Memory = " + Long.toString(total) + "bytes");

特定の時点での残りのヒープメモリは以下のコードで調べることができます。
このコードでは回収できるメモリはできるだけ回収してから残メモリサイズをカウントするため,事前にgcを呼ぶようにしています。
このコードはOutOfMemoryError例外が発生する処理を行う直前の残メモリを調べるときなどに使えるでしょう。
残メモリサイズを表示するJavaプログラムコード
Runtime.getRuntime().gc();
long free = Runtime.getRuntime().freeMemory();
System.out.println("Free Memory = " + Long.toString(free) + "bytes");
※メモリ不足エラーが起きたときは,原因がメモリリークではないかを十分に確認してください。Java VMは参照されなくなったメモリを自動的に回収してくれますが,参照されたままのメモリは回収してくれません。

Javaでの割り当てメモリ拡張方法
Javaアプリケーションのメモリ不足に対する最も手っ取り早い対処方法が,アプリケーション割り当てメモリを増やすことです。
Javaでは,アプリを起動するjavaコマンド([Win版][Solaris版])へのオプション指定で割り当てメモリのサイズを指定することができます。

指定できるオプション指定:
-Xmxサイズ値:割り当てメモリの最大値を指定
-Xmsサイズ値:割り当てメモリの初期値を指定

サイズ値は,-Xmxは2MBより大きい1024の倍数,-Xmsは1MBより大きい1024の倍数でなければなりません。
各サイズ値にキロバイトを指定する場合はkまたはK,メガバイトを指定する場合はmまたはMを付けます。

-Xmxで指定できる値の上限は,OS環境やJavaVMのバージョンにより異なるようです。-Xmxに上限を超える値を指定した場合は「Could not reserve enough space for object heap」というエラーメッセージが返ります。

コマンドラインから起動する場合のオプション指定例:最大値128MB,初期値64MB,起動クラス:EntryClass
java -Xmx128m -Xms64m EntryClass

WebObjectsでメモリサイズを指定するには?

オプション「-Xmxサイズ値」及び「-Xmsサイズ値」をWebObjectsで運用するWebアプリに適用するには以下のようにします。

運用環境で,すでに実稼動しているWebアプリに設定する。
JavaMonitorで以下の設定を行います。
1.JavaMonitorを起動し,Applicationsタブの画面から設定するアプリケーションの「Config」ボタンを押します。
2.「Configuring Application "アプリケーション名"」の画面が表示され,「New Instance Defaults」が開いている状態になります。
3.「New Instance Defaults」の「Additional Arguments:」テキストボックスにオプション「-Xmxサイズ値 -Xmsサイズ値」を入力(追記)して「Push」「Update for New Instances Only」ボタンを押します。
4.アプリケーションのDetail View画面に移動し,アプリケーションを再起動します。

開発版(動作確認用)に設定する。
1.Xcodeにて,プロジェクト名のターゲットをダブルクリックで開きます。
2.「設定」ポップアップで「Development」を選びます。
3.ウインドウの左側リストから「設定」→「シンプルビュー」→「詳細設定ビュー」を開きます。
4.「ビルド設定」が開くので,この中の「JVM_OPTIONS」に「-Xmxサイズ値 -Xmsサイズ値」を入力(追記)します。
5.ウインドウを閉じ,ターゲットをクリーニングしてビルドします。

開発環境でビルドする運用版に設定する。
1.Xcodeにて,プロジェクト名のターゲットをダブルクリックで開きます。
2.ウインドウの左側リストから「設定」→「シンプルビュー」→「詳細設定ビュー」を開きます。
3.「ビルド設定」が開くので,この中の「JVM_OPTIONS」に「-Xmxサイズ値 -Xmsサイズ値」を入力(追記)します。
4.以上の操作をすべてのターゲットのすべての「設定」ポップアップで行います。
5.ウインドウを閉じ,ターゲットをクリーニングしてビルドします。

※上記で指定した内容が,ビルドした運用版Webアプリのパッケージに含まれる各プラットフォーム用クラスパスファイル(例:MacOS用のクラスパスファイルは「Contents/MacOS/MacOSClassPath.txt」)の「# JVMOptions」行に反映されます。

■関連情報
OutOfMemoryError対応事例(@IT:Java Solution)
WebObjects旧版のJavaメモリリーク問題
WebObjects:[API Reference(javadoc)][ADC Tools][サポート]

■関連書籍をAmazonで検索:[Java][WebObjects 和書 洋書]
省メモリプログラミング―メモリ制限のあるシステムのためのソフトウェアパターン集

にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ にほんブログ村 IT技術ブログ ネットワーク・SEへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。


ioPLAZA【アイ・オー・データ直販サイト】ioPLAZA【アイ・オー・データ直販サイト】ioPLAZA【アイ・オー・データ直販サイト】ioPLAZA【アイ・オー・データ直販サイト】

| | トラックバック (0)

MySQL:4.1日本語問題

MySQLは4.0から4.1のバージョンアップで日本語を含む文字コードの扱いが大きく変わっており,それが原因でデータベースで日本語テキストを読み書きするときに文字化けなどが発生するケースがあります。ここではその問題について,当方でわかっている範囲で簡単にまとめてみました。

この問題について,詳しくはMySQLユーザ会FAQページなどを参照してください。

MySQLの文字コード処理は何が変わったのか

MySQL4.1以前は,データベースに格納するテキストデータの文字コードを指定することはできましたが,MySQLがその指定に従って何らかの処理(文字コード変換など)をすることはなく,指定した文字コードは単なるラベルに過ぎなかったようです。
MySQL4.1以降では,指定した文字コードに基づいて次のような処理を行うようになりました。

データベースのスキーマ定義で指定された文字コードとクライアントツールで指定された文字コードが異なる場合,mysqldデーモンとクライアントとの間でデータ転送を行うときに,指定された文字コード間で文字コード変換を行います。
また,このときの文字コード変換は,一度Unicode(UCS-2)に変換してから目的の文字コードに再度変換するという手順になります。

それがどのような影響をもたらしているのか

1)日本語文字コードを指定して作成したデータベースのテキストフィールドに,コマンドラインツール「mysql」から文字コード指定なしでテキストデータを入力したとき,mysqlコマンドの文字コードのデフォルトが「latin1」なので,入力する日本語テキストに対して「latin1→日本語文字コード」の変換を行ってしまい,日本語テキストが壊れます。

2)mysqldデーモンで指定される文字コードのデフォルトが「latin1」なので,データベースを作成するときに文字コードを明示しないと,データベースやテキストフィールドの文字コードはlatin1となります。この状態でmysqlコマンドから日本語文字コードを指定してデータベースに日本語テキストを入力すると「日本語文字コード→latin1」の文字コード変換が起こりますが,latin1には日本語が含まれないため,日本語の文字がすべて「?」に置き換えられてデータベースに書き込まれます。

3)文字コード変換について,Unicodeと非Unicodeを変換する変換テーブルに標準がないため,文字コード変換を行うと一部の文字が意図せぬコードに変換されてしまう可能性があります。詳細はこちらとかこちらとかこちらを参照。なお,文字コード変換は一旦Unicode(UCS-2)に変換してから目的の文字コードに変換するため,非Unicodeから非Unicodeへの変換でもこの問題が発生します。

4)文字コードのデフォルトを変えずにデータベースをlatin1で作成しクライアントからlatin1で読み書きした場合,文字コードが同じなので文字コード変換は起こらずに日本語テキストをデータベースに保存・読み出しができます。ただし,コマンドラインツール「mysqldump」は文字コードのデフォルトが「UTF-8」のため,文字コードをデフォルトのままデータベースの内容をバックアップすると「latin1→UTF-8」の文字コード変換が起きてしまい,日本語テキストが壊れます。

5)JDBCアダプタを介してJavaアプリからデータベースを読み書きした場合,テキストデータはJavaのStringクラスで読み書きを行いますが,Stringクラスのテキストデータは内部でUCS-2で保持するので,データベースアクセスの際にテキストデータの文字コードとUCS-2との間でコード変換が発生するはずです。このときデータベースの文字コードがlatin1なら日本語テキストが壊れ,Unicode系でない場合はUnicodeと非Unicodeの不整合の問題が発生すると思われます。

どうすればいいのか

以下のような設定を行えば,問題は避けられるはずです。
1)MySQLのデータベースに設定する文字コード,及びMySQLに入出力するテキストデータの文字コードを1つに統一して,文字コード変換が起きないようにします。
2)JDBCアダプタからMySQLにアクセスする場合は,MySQLで使用するすべての文字コードにUnicode系を指定して,JavaのStringクラス(UCS-2)との間でUnicode系以外への文字コード変換が起きないようにします。

MySQLでデフォルトの文字コードを設定するには,設定ファイル「my.cnf」(Windowsの場合は「my.ini」)に文字コードの定義を追加します。
MySQLの設定ファイルについてはこちらを参照:[4.1][5.1]
ここで指定できる文字コードのリストはこちらを参照:[4.1][5.1]
Microsoftコードページ932「cp932」はMySQL4.1.12及び5.0.3以降で指定できます。

デフォルトの文字コードの変更については,ソースファイルのリコンパイルによる対応もありますが,mysqldumpについてはソースファイル上での指定にかかわらずUTF-8でリコンパイルされてしまうので,mysqldumpのデフォルト文字コードの変更についてはmy.cnfファイルで対応するしかありません。

my.cnfファイルの[mysqld]セクションで指定できるパラメータに「skip-character-set-client-handshake」があります。このパラメータはクライアントの文字コード設定をサーバの設定で上書きして文字コード変換を行わないようにするようです。この指定はMySQL4.1.15及びMySQL5.0.13以降で使えます。
また,文字コードに「binary」を指定してもMySQL4.1以前同様文字コード変換を行わなくなるようです。但し,データベースやテキストフィールドでbinary型を指定した場合は,テキストの検索や文字列長を指定して行う処理などで不都合が生じるようです。そのため,binaryの指定はクライアントツールに限ったほうがよいようです。

文字コードにUTF-8を指定したmy.cnfファイルの設定例:

[client]
default-character-set = utf8

[mysqld]
default-character-set = utf8
skip-character-set-client-handshake

[mysqldump]
default-character-set = utf8

[mysql]
default-character-set = utf8

注意:my.cnfファイルの設定を更新したら,MySQLを再起動する必要があります。

JDBCアダプタ(MySQL Connector/J)からMySQLにアクセスする場合は,JDBCアダプタがデータベースのクライアントとして動作するときの文字コードを指定しておきます。JDBCアダプタ文字コードはJDBC URLで指定します。
文字コードにUTF-8を指定する場合の設定例(文字コード以外の指定は省いています):
jdbc:mysql://ホスト名/データベース名?useUnicode=true&characterEncoding=UTF8
JDBC URLでのUTF-8設定について,詳細はこちらこちらを参照。

■関連情報
Microsoftコードページ932(Wikipedia
MySQLユーザ会/FAQページ

■関連書籍をAmazonで検索:[MySQL][JDBC]
MySQL徹底入門 第3版 ~5.5新機能対応~ (kindle版)

にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ にほんブログ村 IT技術ブログ ネットワーク・SEへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。
ioPLAZA【アイ・オー・データ直販サイト】

| | トラックバック (0)

WebObjects:MySQLのためのEOModelの設定

WebObjectsの運用環境で稼動するWebアプリケーションからデータベースにアクセスするためには,データベースの情報を定義するEOModelファイルが必要です。このEOModelファイルはEnterprise Objects Framework(EOF)からJDBCアダプタを介してデータベースにアクセスするためのもので,データベースへのアクセスに必要なJDBCの定義を設定しておく必要があります。
当方では,データベースはもっぱらMySQLを使っていますが,その場合にEOModelファイルに設定しているJDBCの定義をサンプルとして以下に公開します。
MySQLのバージョンは5.0.xで,JDBCアダプタはMySQL Connector/J 5.0.xを使用しています。JDBCアダプタは,Mac OS Xの環境では「/Library/Java/Extensions/」にインストールしています。(参考

JDBC Connectionの設定:

名称設定値
JDBC URL:jdbc:mysql://ホスト名/データベース名?capitalizeTypeNames=true&useUnicode=true&
characterEncoding=UTF8&tinyInt1isBit=false&autoReconnect=true&maxReconnects=3
UserName:MySQL上に作成した,Webアプリからアクセスするデータベースのユーザ名。
Password:同パスワード。
Driver:当方では空白で接続できていますが,「com.mysql.jdbc.Driver」を指定する例もあるようです。
Plugin:空白でOKです。
注:JDBC URLはレイアウトの関係で途中改行を入れていますが,実際は1行です。

JDBC URLで設定した各パラメータについての解説

ホスト名
MySQLが稼動しているホスト名またはIPアドレスを指定します。
WebObjects運用環境とMySQLが同じホストで稼動しているなら,ホスト名は「localhost」または「127.0.0.1」になります。

データベース名
MySQL上に作成した,Webアプリからアクセスするデータベース名を指定します。

capitalizeTypeNames=true
タイプ名を大文字にします。
ドキュメントによると,WebObjectsから呼ぶときはこれを有効にしておくことになっているらしいです。

useUnicode=true
Unicode系の文字エンコーディングを使用することを宣言します。
MySQL 5.0.xではデフォルトがtrueです。

characterEncoding=UTF8
文字エンコーディングをUTF-8に指定します。
MySQLが5.0になって,データベースごと,テキストフィールドごとに文字コードを指定できるようになりましたが,その指定を行った場合はここにはUTF-8を指定することになっているようです。→こちらの最後を参照。
ここで指定した文字コードがデータベースに書き込まれるのは,データベースの文字コードに「binary」とか指定したときに有効なのではないかと思われます。
useUnicodeとcharacterEncodingについての詳細はこちらを参照。

tinyInt1isBit=false
TINYINT(1)を8bit値として扱います。詳細はこちらを参照。
MySQLの旧バージョンにアクセスするプログラムとソースコードを共通化するために,MySQL5.0.xでもTINYINT(1)は8bit値として扱うようにしています。

autoReconnect=true
データベースへクエリを送信する前にデータベースとの接続を確認し,接続が切れていれば再接続を試みます。
ただし,再接続を“安全に”行うことはできず,autoReconnectの機能は将来バージョンで廃止になるようです。
接続が切れる例としては,mysqldはデフォルトでアイドル状態が8時間続いた接続を閉じてしまいます。
この接続が切れるまでのアイドル時間は,「my.cnf」ファイルの[mysqld]セクションで定義する「wait_timeout」(または「interactive_timeout」)パラメータにより指定されます。

maxReconnects=3
autoReconnect=trueのときに再接続を試みる最大の回数です。
注:このパラメータは,MySQL Connector/Jの5.0のドキュメントには記載がありますが,5.1のドキュメントからはなくなっています。

■関連情報
WebObjects:JDBC URL を指定してデータベースサーバの文字エンコードを選択する方法
MySQL 5.1:MySQL Connector/J よくある問題と解決法
MySQL Connector/Jに対してJDBC URLで指定できるパラメータ:[5.0][5.1]
Enterprise Objects Frameworkの解説(Wikipedia)
WebObjects:Javaライブラリの利用方法
WebObjects:[API Reference(javadoc)][ADC Tools][サポート]

■関連書籍をAmazonで検索:[MySQL][WebObjects 和書 洋書][JDBC]
実践 JDBC―Javaデータベースプログラミング術

にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。


ノートンモバイルセキュリティバナーブックオフオンライン【PC・携帯共通】

| | トラックバック (0)

« 2008年1月 | トップページ | 2008年3月 »