2008年3月21日金曜日

SpringFrameworkとHibernateの連係 -HibernateDaoSupport編-

HibernateDaoSupportを利用したSpringFrameworkとHibernateの連係を調べてみました。
 参考: Implementing Spring-based DAOs without callbacks

HibernateTemplateを利用してDAOを実装する代わりに、Hibernateアクセスコードをコールバック内にラップすることをせずに、データアクセスコードを従来の方法で記述することも可能です。HibernateDaoSupportを基にしたクラスは、従来のトランザクションベースのセッションや、例外の変換メソッドを備えています。これらのコードは、トランザクション内で必ず処理させるため、getSession()メソッドのallowCreateに通常falseを渡します。

public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {

public Collection loadProductsByCategory(String category) throws DataAccessException, MyException {
Session session = getSession(false);
try {
Query query = session.createQuery("from test.Product product where product.category=?");
query.setString(0, category);
List result = query.list();
if (result == null) {
throw new MyException("No search results.");
}
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
}
}

この手法の長所は、データへアクセスするコードでアプリケーション独自の例外をスローできる点です(一方HibenrateTemplateクラスでは、callback内でアプリケーション独自の例外をスローすることはできません)。但し、独自のチェックルーチンや例外をcallbackの後に実装することもできるので、依然HibernateTemplateを利用できます。
一般的には、HibernateTemplateクラスの便利なメソッドはシンプルで、たいていの場合に適しています。

「つまりたいていの場合はHibernateTemplateを使ったほうがいいよ」ということでしょうか。

2008年3月19日水曜日

Hibernateの設定


Hibernateの設定をまとめてみます。

 参考: Chapter 3. Configuration (Hibernate v.3 Documentation)

SessionFactoryの取得

すべてのマッピングファイルがパースされ後、Sessionインスタンス用のファクトリを取得しなければなりません。このファクトリはアプリケーションの全スレッドで共有されます。

SessionFactory sessions = cfg.buildSessionFactory();

Hibernateでは複数のSessionFactoryをインスタンス化でき、これは複数データベースを利用する際に便利です。

JDBCコネクション

データベースへのアクセスが必要な処理を行う際にコネクションプールからJDBCコネクションを自動取得するには、JDBCコネクションを設定する必要があります。
主なプロパティは
  • hibernate.connection.driver_class
    jdbc driver class
  • hibernate.connection.url
    jdbc URL
  • hibernate.connection.username
    database user
  • hibernate.connection.password
    database user password
  • hibernate.connection.pool_size
    maximum number of pooled connections

Hibernateのコネクションプール用アルゴリズムは必要最小限なもので、製品やパフォーマンステスト向けのものではありません。その場合HibernateのlibディレクトリにあるC3P0などを利用してください。
C3P0をコネクションプールとして利用する場合は、以下のようなhibernate.c3p0.*プロパティを設定する必要があります。
hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
hibernate.connection.username = myuser
hibernate.connection.password = secret
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

必須ではない設定
  • hibernate.dialect (方言)
    特定のリレーショナルデータベース向けに最適化されたSQLを発行するために、クラス名を指定する。
    (PostgreSQL: org.hibernate.dialect.PostgreSQLDialect、MySQL: org.hibernate.dialect.MySQLDialect eg...)

  • hibernate.show_sql
    コンソールにSQLを出力するか否かを指定する。(true|false)
  • hibernate.format_sql
    コンソールやログにSQLを出力する際に成型するか否か。(true|false)
  • hibernate.max_fetch_depth
    1対1や多対1関連に対してouterジョインをする際のどこまで辿るかを指定する。推奨は0(辿らない)~3。

Hibernateのアーキテクチャ

Hibernateを一通り使ったけど詳しいことを知らないので、どんな塩梅かちょこっと調べてみました(誤訳あり)。

 参考: Architecture (Hibernate v.3 Documentation - Chapter 2)


用語の定義

SessionFactory
 単一データベース用のコンパイル済みマッピングのスレッドセーフなキャッシュで、SessionのファクトリかつConnectionProviderのクライアント。トランザクション間で再利用可能な2次キャッシュを、場合によって提供する。

Session
 アプリケーションと永続化ストア間のやり取りを表す、シングルスレッドで短命なオブジェクト。JDBCコネクションをラップしたTransanctionのファクトリ。また、データの1次キャッシュ(idでオブジェクトを検索した場合や、オブジェクトの関連を辿る場合に利用される)を提供する。

Persistent objects and collections
 永続化状態とビジネスファンクション(?)を保持する短命な単一スレッドのオブジェクトで、ほぼJava Beans/POJO。異なる点は、唯一のSessionに関連付けられているということ。Sessionがクローズされるとデタッチされ、アプリケーション層で自由に利用できる。

Transient and detached objects and collections

 Sessionと関連づいていない永続化クラスのインスタンス。アプリケーションによってインスタンス化されまだ永続化されていないか、クローズされたSessionによってインスタンス化されたもの。

Transaction

 アプリケーションで処理のアトミック性を定めるために利用する、シングルスレッドで短命なオブジェクト。Sessionは複数Transactionに跨る場合もあるが、Transactionはそれ以上分割できない。

ConnectionProvider

 JDBCコネクションのファクトリで、DataSourceまたはDriverManager由来のアプリケーション。アプリケーションで利用できないが、カスタマイズできる。

TransactionFactory
 Transactionのファクトリで、アプリケーションで利用できないがカスタマイズできる。

インスタンスの状態について

 Sessionの状態を考慮し、永続化クラスのインスタンスは3つの状態の何れかになる。
  • transient
     インスタンスがSessionと関連付けられておらず、主キーの値がセットされていない状態。

  • persistent
     Sessionと関連付けられたインスタンスで、主キーの値がセットされておりデータベースの行と一致する。特殊な永続化コンテキストでは、永続化IDとJava ID(オブジェクトのメモリー内の場所)とが一致する。

  • detached
     既にクローズされた永続化コンテキストと関連付けられていたか、他のプロセスにシリアライズされたインスタンス。永続化IDがセットされており、データベースの行と一致する場合が多い。
 

SpringIDEのインストール(Eclipse用SpringFrameworkプラグイン)

EclipseにSpringFrameworkのプラグインをインストールしてみました。

インストール方法は簡単で、「Feature Updates」で「Search for new features to install」を選択して、「Update sites to visit」の「New Remote Site」ボタンで

   http://springide.org/updatesite

を登録するだけです。その際Aspect Jのプラグイン(?)も必要になるようなので、併せてインストールしました。

以上です。

2008年3月18日火曜日

SpringFrameworkとHibernateの連係 -HibernateTemplate編-

SpringFrameworkとHibernateを連携する方法を調査してみました

参考: Chapter 12. Object Relational Mapping(ORM) data access

SessionFactoryの設定

リソースルックアップのハードコードを避けるために、SpringFrameworkではJDBCデータソースやHiberanteのSessionFactoryなどのリソースをビーンとして定義することができます。

<beans>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432"/Tomcat/>
<property name="username" value="tomcat"/>
<property name="password" value="password"/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingResources">
<list>
<value>マッピングファイル1.hbm.xml</value>
</list>
<list>
<value>マッピングファイル2.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
</value>
</property>
</bean>
</beans>

HibernateTemplate

DAOもしくはビジネスサービスのメソッドの基本的なプログラムモデルは以下のようになります。

public class ProductDaoImpl implements ProductDao {

private HibernateTemplate hibernateTemplate;

public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}

public Collection loadProductsByCategory(String category) throws DataAccessException {
return this.hibernateTemplate.find("from test.Product product where product.category=?", category);
}
}

オブジェクトの実装に関して特に制限はありませんが、SessionFactoryを渡してやる必要があります。SessionFactoryはどこからでも呼び出せますが、できればSpring IOCコンテナからsetSessionFactory()メソッドを利用して、Beanとして呼び出します。その例を以下に示します。

<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
</beans>

HibernateTemplateクラスは上記のような便利なメソッドのほか、HiberanteのSessionインタフェースで公開されているメソッドを備えています。HiberanteTemplateにないメソッドを利用しようとしてSessionクラスへ直接アクセスするには、以下のようなコールバックベースの低レベルの方法をとることもできます。

public class ProductDaoImpl implements ProductDao {

private HibernateTemplate hibernateTemplate;

public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}

public Collection loadProductsByCategory(final String category) throws DataAccessException {
return this.hibernateTemplate.execute(new HibernateCallback() {

public Object doInHibernate(Session session) {
Criteria criteria = session.createCriteria(Product.class);
criteria.add(Expression.eq("category", category));
criteria.setMaxResults(6);
return criteria.list();
}
};
}
}
HibernateTemplateのAPI

 参考: Classs HibernateTemplate

Hibernateのデータアクセス処理を簡素化するヘルパークラス。org.springframework.daoの例外ヒエラルキーに沿ってHibernateExceptionをDataAccessExceptionへ自動的に変換します。
execute()が主となるメソッドで、HibernateCallbackインタフェースを実装したHibernateのアクセスコードを備えています。また、セッションの制御機能も備えており、Hibernateセッションの取得やクローズや関連した例外処理をする必要はありません。

2008年3月17日月曜日

DBスキーマからのコード自動生成 (HibernateToolsプラグインの利用)

HibernateToolsを利用することでDBスキーマからドメインクラスを自動生成することができます。

hiberante.cfg.xmlファイルとConsole設定ファイルの作成


初 めにConfiguration Wizardを利用してhibernate.cfg.xmlファイルを作成します。
EclipseでTomcatプロジェクトを作成した後、WEB-INF/libディレクトリにPostgreSQLドライバをインポートしておきます。

Package Explorerでプロジェクトを右クリックし、「New」→「Other」→「Hibernate」→「Hiberante Configuration File (cfg.xml)」を選択します。

「Create Hiberante Configuration file(cfg.xml)」画面でhibernate.cfg.xmlファイルの保存先としてWEB-INF/srcを指定します。

次の画面でデータベースの接続情報を設定します。ここではPostgreSQLへ接続することにします。ここで、「Create a console configuration」にチェックを入れます。

「Create Hibernate Console Configuration」の「Classpath」タブでWEB-INF/libディレクトリにインポートしたPostgreSQLのドライバ(jarファイル)を指定し、「Finish」ボタンをクリックします。


Reverse engineerファイルの作成

ドメインクラスを自動生成するためのReverse Engineerファイルを作成します。
Package Explorerでプロジェクトを右クリック→「New」→「Other」→「Hibernate」→「Hibernate Reverse Engineering File(reveng.xml)」をクリックします。

「Create Hibernate Reverse Engineering file(reveng.xml)」でhibernate.reveng.xmlファイルの保存先としてWEb-INF/srcディレクトリ指定します。

「Configure Table fileters」の「Console configuration」でconsoleの設定ファイルを指定し、「Refresh」ボタンをクリックします。そうすると設定が間違っていなければ データベースへ接続しスキーマを取得します。

ドメインクラスを作成するテーブルやビューを選択し「Include」ボタンをクリックし、「Finish」ボタンをクリックします。


ドメインクラスの自動生成


最後にデータベースに接続し、ドメインクラスを自動生成します。


EclipseのツールバーにあるHibernateボタンをクリックしドロップ ダウンメニューから、「Open Hibernate Code Generation Dialog...」をクリックします。

「Hibernate Code Generation」を右クリックし「New」をクリックします。

「Main」 タブの「Console Configuration」に、コンソール設定ファイル及びコードを出力するディレクトリを「Output directory」で指定します。その後「Reverse engineer JDBC Connection」にチェックを入れ、自動生成するコードのパッケージ名や先ほど作成したreveng.xmlファイルを指定します。


「Exporters」タブで自動生成する内容を指定します(参考)。その後「Run」ボタンをクリックしコードを自動生成します。

コード自動生成に成功すると指定したパッケージ名でWEB-INF/srcディレクトリ以下に出力されます。

以上です。

2008年3月14日金曜日

Hibernate + Eclipse開発環境の構築

O/RマッパーとしてHibernateを利用してアプリケーションを開発する環境を構築してみます。最終的に、データベースからのクラス自動生成まで行えるようにします。また、Hibernateは3.2.6を、Eclipseは3.3.2を、データベースはPostgreSQL-8.3.0を前提条件とします。

Hibernate Tools Documentation


Eclipseプラグインについて

Hibernate ToolsのEclipseプラグインでは以下のような機能が利用できます。
  • Mapping Editor: Hibernate XMLマッピングファイル用エディタ
  • Hibernate Console: Hibernate Console設定やpersistentクラスとその関連を俯瞰することができる
  • Configuration Wizards and Code generation: Hibernate設定ファイル用のウィザード(この設定ファイルで、データベーススキーマからのクラスファイル自動生成[reverse engineer]などができる)
  • Eclipse JDT integration
導入方法

Eclipseを起動し新規プラグインのアップデートサイト指定画面でHibernateToolsのURL(http://download.jboss.org/jbosstools/updates/stable)を指定します。その後「Hibernate Tools」→「JBossTools Development Release: 2.0.0.GA」→「Hibernate Tools 3.2.0.GA」にチェックを入れインストールします(尚、Eclipse Plug-in Development Environmentが入ってないとインストールできないようです)

2008年3月12日水曜日

managerのみMemoryRealmを利用する

servletの制御をおこなうmanagerアプリケーションのみMemoryRealmを利用するようにできるか調べてみました。
これは、managerアプリケーションとDBを利用するウェブアプリケーションをTomcat上に構築した際に、managerアプリケーションのRealmをDBに入れたくないためです(JDBCRealmで利用するテーブル構造が気に入らないのです)。
Apache Tomcat 6.0のリファレンスを参考にRealmを調べてみると、
Inside a <context> element</context> - This Realm will be used ONLY for THIS web application.
とあるので、CATALINA_HOME/conf/Catalina/localhost/manager.xmlのContextタグ内にRealmタグを付ければよいことになります。というわけでmanager.xmlを以下のようにしてみました。

<Context path="/manager" debug="0" privileged="true">
<Realm className="org.apache.catalina.realm.MemoryRealm"/>
</Context>


これでmanagerアプリケーションのみMemoryRealmを利用するようになったはずです。

さて、MemoryRealmに記載したパスワードはデフォルトでプレインテキストになっているので、これをダイジェストにしてみます。
それには、Realmタグにdigestプロパティを追加すればよくその値として、jaav.security.MessageDigestクラスがサポートしている
MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512が設定できるようです(Java 6のリファレンス)。
肝心のダイジェストの作成方法ですが、環境変数CATALINA_HOMEとしてTomcatのホームディレクトリが設定されているとして、以下のようにして作成できます。

java -cp %CATALINA_HOME%\lib\catalina.jar;%CATALINA_HOME%\bin\tomcat-juli.jar \
org.apache.catalina.realm.RealmBase -a SHA-256 プレインテキスト


ここで得られた文字列をtomcat-users.xmlのパスワードにコピーし、manager.xmlを以下のように修正します。


<Context path="/manager" debug="0" privileged="true">
<Realm className="org.apache.catalina.realm.MemoryRealm" digest="SHA-256"/>
</Context>

以上です。

2008年3月11日火曜日

PostgreSQLのインストール

PostgreSQL-8.3.0をWindows XPにインストールします。

  1. PostgreSQLのHPからWindows用のバイナリファイルをダウンロードし適当なディレクトリに解凍します。

  2. 解凍したフォルダに含まれるSETUP.batを実行し、「Welcome to the PostgreSQL Installation Wizard」で「Japanese/JAPAN」を選択します。

  3. 「インストールオプション」画面で「データ・ディレクトリ」、「アプリケーションスタックビルダ」、「ユーザーインターフェース」を指定します。

  4. 「サービス構成」でアカウント「postgresql」を設定します(無ければ作成してくれます)。

  5. 「データベースクラスタの初期化」で「ロケール」にJapanese, Japanを指定し、スーパーユーザーなどのパラメータを設定します。

  6. 「貢献モジュールを可能にする」では「Adminpack」のみチェックします。

  7. 「インストールは完了しました」で「スタックビルダを使って終了する」にチェックが入っていることを確認し、「終わる」ボタンをクリックします。

  8. スタックビルダの最初の画面で「PostgreSQL Database Server 8.3選択(5432から)」を選択します。
  9. インストールしたいアプリケーションとして「Database Drivers」の「psqlJDBC 8.3.xx」を選択します。
  10. あとはウィザードに沿ってJDBCドライバをインストールします。
  11. インストールが完了したらpgAdminを起動し、インストール時に設定したスーパーユーザーでログインできることを確認します。
以上です。

Tomcatユーザ認証(MemoryRealm)

Tomcatのアプリケーションマネージャ(Servletを制御するアプリケーション)はアクセスする際にユーザ認証を利用していますが、そのユーザ認証にデータベースを利用する方法を調べてみました。

データベースでのユーザ認証を行う前に通常のファイルベースのユーザ認証を、まず試してみます。
なおTomcatのバージョンは6.0.16を前提とします。

Tomcatのドキュメントを参考に設定してみます。

  1. CATALINA_HOME/conf/Catalina/localhost/manager.xmlとして以下の内容を記載します。これによりローカルホストからのみmanagerアプリケーションにアクセスできるようになります。

    <Context path="/manager" debug="0" privileged="true">
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
    allow="127\.0\.0\.1"/>
    <Context>

  2. CATALINA_HOME¥cont¥tomcat-users.xmlの<tomcat-users>タグ内にユーザの設定を記載します。
    <user name="ログインユーザー名" password="ログインパスワード" roles="manager"/>

    もしくはEclipseの「Window」→「Preferences...」→「Tomcat」→「Tomcatアプリケーション・マネージャー」でユーザー名とパスワードを入力し「tomcat-users.xmlにユーザーを追加」ボタンをクリックすることで同じ操作が行われます。

  3. EclipseでTomcatを起動し、ブラウザでhttp://localhost:8080/manager/へアクセスします。その際tomcat-users.xmlで指定したログインユーザー名とパスワードを入力します。

  4. Tomcat Webアプリケーションマネージャ画面が表示されることを確認します。
以上でMemoryRealmを利用したユーザ認証の設定は終了です。