この章では、Java Persistence API (JPA)を使用してオブジェクト・リレーショナル・マッピングを実行する方法を学習します。この章では次の項について説明します。
実用バージョンのOracle Database Express Edition(OracleXE データベース)がシステムにインストールされている必要があります。このデータベースがない場合には、次のURLからダウンロードできます。
http://www.oracle.com/technology/software/products/database/xe/index.html
Enterprise JavaBeans(EJB)テクノロジの主要な強化点はJPAの追加です。これにより、エンティティ永続性モデルが簡略化され、Java SEの永続性など以前のEJBテクノロジにはなかった機能が追加されます。
JPAでは、リレーショナル・データをJavaオブジェクト(永続性エンティティ)にマップする方法や、これらのオブジェクトをリレーショナル・データベースに格納して後でアクセスできるようにする方法のほか、エンティティを使用するアプリケーションが終了してもそのエンティティの状態を存続させる方法を定義します。エンティティ永続性モデルを簡略化する以外に、JPAはオブジェクト・リレーショナル・マッピングを標準化します。
Coherenceクラスタ内にデータを格納する方法を決定するには、バッキング・マップを使用します。デフォルトでは、Coherenceではメモリーベースのバッキング・マップが使用されます。データを永続化するために実装されるバッキング・マップには、複数のものがあります。
この演習で使用するJPA実装には、Java環境からデータベース環境へのオブジェクト・リレーショナル・マッピング(ORM)が用意されています。そのため、標準的なCoherenceのgetメソッドやputメソッドを使用したり、JPAおよび(オープン・ソースのEclipseLinkプロジェクトに基づき)Oracle TopLinkを使用してCoherenceコールをデータベース・コールに変換したりすることもできます。
この演習では、Eclipseを使用して次のタスクを実行します。
OracleXEデータベースでHRスキーマへの接続を作成します。
EMPLOYEES表に対するJPAオブジェクトを自動生成します。
cache-server.cmdファイルを変更して、サンプルJPA cache-config.xmlファイルをポイントするようにします。
インストール済のOracleXEデータベースでHRアカウントのロックを解除します。
使用するシステムにOracleXEデータベースをインストールし、HRスキーマにアクセスできるようにしておく必要があります。HRアカウントのロックを解除するには:
「スタート」→「すべてのプログラム」→「Oracle Database Express Edition」→「SQLコマンドラインの実行 」の順に移動します。
connect system as sysdbaと入力し、パスワードを要求されたらwelcome1と入力します(注意: ユーザー名はsystem、パスワードはwelcome1です)。
次のコマンドを入力してアカウントのロックを解除します。
alter user hr identified by hr account unlock;
この演習では、org.eclipse.persistence.*ファイルとjavax.persistenceファイルがシステムに存在している必要があります。これらのファイルは、Eclipse IDEを使用して取得できます。
「Help」→「Eclipse Marketplace」を選択します。
「Eclipse Marketplace」ダイアログ・ボックスで、「Find>」フィールドにEclipseLinkと入力して、「Go」をクリックします。
図8-3に示されているように「EclipseLink SDK」を選択し、インストールの指示に従います。必要な永続性ファイルをeclipse\pluginsディレクトリにインストールします。
Eclipse IDE内にJPAという新規プロジェクトを作成します。詳細は、「Eclipse IDEでの新規プロジェクトの作成」を参照してください。
Eclipse IDEで、「Window」→「Open Perspective」→「Other」をクリックし、「Open Perspective」ダイアログ・ボックスを開きます。図8-4に示されているように、「JPA perspective」を選択します。
図8-4 「Open Perspective」ダイアログ・ボックス内でのJPA Perspectiveの選択

「File」→「New」→「JPA Project」を選択します。プロジェクト名にJPAと入力します。デフォルトの場所がhome\oracle\workspace\JPAをポイントしていることを確認します。「Configuration」フィールドで「Modify」をクリックし、「Project Facets」ダイアログ・ボックスを開きます。
「Oracle Coherence」ファセットを選択します。「JPA」ファセットが選択されている必要があります。
「Configuration」フィールドで「Save As」をクリックします。「Save Preset」ダイアログ・ボックスでJPAConfigurationと入力し、「OK」をクリックします。「Project Facets」ダイアログ・ボックスの内容は図8-5のようになります。
「New JPA Project」ダイアログ・ボックスの内容は、図8-6のようになります。「Next」をクリックして「Java」ページへ移動します。
「Java」ページで「Next」をクリックして、デフォルトの出力先フォルダの場所を受け入れます。
Coherence37のユーザー・ライブラリが「Coherence」ページで選択されている必要があります。「Next」をクリックします。
「JPA Facet」ページの「Platform」ドロップダウン・リストで「EclipseLink 2.1.x」を選択します。EclipseLinkファイルをダウンロードするには、「Download library」アイコンをクリックします。「Download Library」ダイアログ・ボックスで、図8-7に示されているように「EclipseLink 2.1.2 - Helios」を選択します。
「Next」をクリックしてライセンス契約を受け入れ、「Finish」をクリックします。
ライブラリのダウンロード後、「JPA Facet」ページは次のようになります:
Oracle XEデータベースへの接続を作成します。「Add connection」をクリックします。
「Connection Profile」ダイアログ・ボックスで、図8-9に示されているように「Oracle Database Connection」を選択して、「Name」フィールドにXE_HRと入力します。「Next」をクリックします。
「Drivers」フィールドで「Oracle Database 10g Driver Default」を選択します。「General」タブを編集します。「User name」フィールドにhr、「Password」フィールドにhrと入力します。「Save Password」チェック・ボックスを選択します。「Host」フィールドにlocalhostと入力します。「Connect when the wizard completes」チェック・ボックスを選択します。「Test Connection」ボタンをクリックします。テストで、図8-10に示されているような成功メッセージが表示された警告ボックスが返されます。「OK」→「Next」をクリックします。
図8-10 「New Connection Profile」ダイアログ・ボックスおよび成功メッセージ

「JPA Facet」ページで、「Add driver library to build path」→「Finish」をクリックします。
永続性ユニットには、メタデータ・ファイル、クラス、およびグループとしての永続に必要なすべてのクラスを含むJARのセットを識別する簡単な方法が備わっています。永続性ユニットは、その名前によって識別されます。エンティティBeanは永続データを持つEnterprise Java Beanであり、永続データ・ストアに保存できます。JPAエンティティBeanは、永続性ユニットに属すことができます。永続性ユニットは、persistence.xmlファイルにより記述されています。
JPA永続性ユニットとJPAエンティティBeanを作成するには:
JPAプロジェクトを右クリックし、「New」→「Entities from Tables」を選択します。「Select Tables」ダイアログ・ボックスが開きます。
図8-11に示されているようにEMPLOYEES表を選択し、「Next」をクリックします。
「Table Associations」ページで、図8-12に示されているように、「Next」をクリックしてデフォルト設定を受け入れます。
「Customize Default Entity Generation」ページで、「Collection properties type」のjava.uitil.Listを選択し、「Package」フィールドにcom.oracle.handsonと入力します。
終了すると、「Customize Default Entity Generation」ページは図8-13のようになります。「Next」をクリックします。
「Customize Individual Entities」ページで、表示されているデフォルト設定を受け入れ、「Finish」をクリックしてJPAエンティティを生成します。
persistence.xmlファイルは1つまたは複数の永続性ユニットを定義します。Eclipse IDEでpersistence.xml Editorツールを使用して、persistence.xmlファイルを編集します。
Eclipseエディタでpersistence.xmlファイルを開きます。
「一般」タブをクリックします。永続性プロバイダの名前を入力します。org.eclipse.persistence.jpa.PersistenceProviderという名前です。
「Connection」タブで、「Transaction type」ドロップダウン・リストから「Resource Local」を選択します。
「JDBC connection properties」セクションで、「Populate from connection」リンクをクリックします。このフィールドの値は、「JPAに対するプロジェクトの構成」で定義したデータベース接続に基づいて設定されます。「Connection Properties」タブは、図8-16のようになります。
図8-16 persistence.xmlエディタの「Connection Properties」タブ

「Properties」タブを調べます。内容は図8-17のようになります。
「Source」タブを開きます。persistence.xmlファイルは例8-1のようになります。
例8-1 生成されたpersistence.xmlファイル
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="JPA" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>com.oracle.handson.Employees</class>
    <properties>
      <property name="eclipselink.target-server" value="None"/>
      <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
      <property name="javax.persistence.jdbc.user" value="hr"/>
      <property name="javax.persistence.jdbc.password" value="hr"/>
      <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
    </properties>
  </persistence-unit>
</persistence>
JPAプロジェクトに対するキャッシュ構成ファイルを作成します。
coherence-cache-config.xmlファイルを右クリックして、「Open」を選択します。
例8-2のようにコードを入力します。「Save As」を使用して、jpa-cache-config.xmlという名前でファイルを保存します。ファイルはhome\oracle\workspace\JPA\srcフォルダに保存されます。
例8-2 JPAに対するキャッシュ構成
<?xml version="1.0" encoding="windows-1252" ?>
<cache-config>
  <caching-scheme-mapping>
    <cache-mapping>
      <!-- Set the name of the cache to be the entity name  -->
      <cache-name>Employees</cache-name>
      <!-- Configure this cache to use the scheme defined below  -->
      <scheme-name>jpa-distributed</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>
  <caching-schemes>
    <distributed-scheme>
      <scheme-name>jpa-distributed</scheme-name>
      <service-name>JpaDistributedCache</service-name>
      <backing-map-scheme>
        <read-write-backing-map-scheme>
          <!--
      Define the cache scheme
      -->
          <internal-cache-scheme>
            <local-scheme/>
          </internal-cache-scheme>
          <cachestore-scheme>
            <class-scheme>
              <class-name>com.tangosol.coherence.jpa.JpaCacheStore</class-name>
              <init-params>
                <!--
            This param is the entity name
            This param is the fully qualified entity class
            This param should match the value of the
            persistence unit name in persistence.xml
            -->
                <init-param>
                  <param-type>java.lang.String</param-type>
                  <param-value>{cache-name}</param-value>
                </init-param>
                <init-param>
                  <param-type>java.lang.String</param-type>
                  <param-value>com.oracle.handson.{cache-name}</param-value>
                </init-param>
                <init-param>
                  <param-type>java.lang.String</param-type>
                  <param-value>JPA</param-value>
                </init-param>
              </init-params>
            </class-scheme>
          </cachestore-scheme>
        </read-write-backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </distributed-scheme>
  </caching-schemes>
</cache-config>
オリジナルのcoherence-cache-config.xmlファイルをProject Explorerから削除します。
JPAプロジェクト用キャッシュ・サーバーを起動するための構成を作成します。
プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「Name」フィールドにJPACacheServerと入力します。
「Main」タブで、「Project」フィールドの「Browse」をクリックし、「Project Selection」ダイアログ・ボックスでJPAプロジェクトを選択します。「Include system libraries when searching for a main class」チェック・ボックスを選択し、「Search」をクリックします。「Select Type」フィールドにDefaultCacheServerと入力して、com.tangosol.net.DefaultCacheServerを選択します。「OK」をクリックします。「Main」タブは図8-18のようになります。
「Coherence」タブの「General」タブで、「Topology」の下のキャッシュ構成ファイルへのパスを指定します。「Browse」ボタンをクリックして、JPAキャッシュ構成ファイルC:\home\oracle\workspace\JPA\src\jpa-cache-config.xmlの絶対ファイル・パスに移動します。「Local storage」の下の「Enabled (cache server)」を選択します。「Cluster port」には3155などの一意の値を入力します。
「Other」タブで、tangosol.pof.configの項目がデフォルトのpof-config.xmlに設定されていることを確認します。
「Common」タブで、「Shared file」を選択して\JPAプロジェクトを参照します。
「Classpath」タブで、「User Entries」→「Add External JARs」をクリックして、リストにcoherence-jpa.jarファイルを追加します。「Apply」をクリックします。
「Classpath」タブは図8-19のようになります。
JPAプロジェクト内にEmployeesオブジェクトとやり取りするための新規クラスを作成します。このクラスは、従業員のサラリーの値を変更する目的で作成されます。
RunEmployeeExampleというmainメソッドを持つ新規クラスを作成します。詳細は、「Javaクラスの作成」を参照してください。
次のタスクを実行するコードを作成します。
EMPLOYEE_ID属性を使用して従業員を取得します。EMPLOYEE_IDはlongデータ・タイプです。
サラリーを表示します。
従業員の昇給を10%にします。
値を再度取得して、昇給を確定します。
例8-3は、考えられるRunEmployeeExampleクラスの実装を示しています。
例8-3 従業員クラスのサンプル・ファイル
package com.oracle.handson;
import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import java.math.BigDecimal;
public class RunEmployeeExample 
    {
    public RunEmployeeExample() 
    {
    }
    public static void main(String[] args) 
        {
        long empId = 190L;  // emp 190 - Timothy Gates
        
        NamedCache employees = CacheFactory.getCache("Employees");
        
        Employees emp = (Employees)employees.get(empId);   
        
        System.out.println("Employee " + emp.getFirstName() + " " + 
                        emp.getLastName() + ", salary = $" + emp.getSalary() );
        
        // give them a 10% pay rise
        emp.setSalary(emp.getSalary().multiply(BigDecimal.valueOf(1.1)));
        
        employees.put(empId, emp);
        
        Employees emp2 = (Employees)employees.get(empId);
        
        System.out.println("New Employee details are " + emp2.getFirstName() + " " + emp2.getLastName() + ", salary = $" + emp2.getSalary() );
       }
}
実行構成を作成するには、実行時のプロパティを変更してEclipseのクラス・パスを編集します。
「Project Explorer」のRunEmployeeExample.javaを右クリックし、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「New launch configurations」アイコンをクリックします。「Name」フィールドに、RunEmployeeExampleと入力します。
「Main」タブで、「Browse」をクリックし、JPAプロジェクトを選択します。「Main class」フィールドで、「Search」をクリックしてcom.oracle.handson.RunEmployeeExampleを選択します。「Apply」をクリックします。
「Coherence」タブの「General」タブで、「Cache configuration descriptor」フィールドのC:\home\oracle\workspace\JPA\src\jpa-cache-config.xmlファイルを参照します。「Disabled (cache client)」ボタンを選択します。「Cluster port」フィールドに3155と入力します。「Apply」をクリックします。
「Other」タブで、デフォルトのpof-config.xmlがtangosol.pof.configフィールドに表示されていることを確認します。
「Classpath」タブで、「Add External JARs」をクリックしてcoherence-jpa.jarファイルを「User Entries」に追加します。
「Up」ボタンと「Down」ボタンを使用して、Coherence37を「Bootstrap Entries」の先頭に移動します。「Apply」をクリックします。
「Classpath」タブは図8-20のようになります。
Employeesクラスに対してJPAを使用してデータベースに永続化するように注釈を付け、データベースの場所をJPAに知らせるpersistence.xmlファイルを追加したので、CoherenceではCacheStore実装が採用され、JPAを使用してオブジェクトがデータベースにロードおよび格納されます。get(Object key)メソッドを使用すると、次のことが実行されます。
Coherenceで、キーを持つエントリが検索されます。
このエントリがまだキャッシュされていない場合や、期限切れでキャッシュから削除されている場合には、バッキング・マップがコールされ、jpaとeclipselinkを使用してデータが取得されます。
このエントリがキャッシュ内にある場合には、eclipselinkを経由しないでエントリがアプリケーションに直接返されます。put(object key,object value)メソッドを使用すると、eclipselink経由でjpaが使用され、データベースへの変更がすべて永続化されます。
「Run」をクリックしてRunEmployeeExample構成を実行します。プログラムからの出力は例8-4のようになります。
例8-4 RunEmployeeExampleプログラムからの出力
...
TcpRing{Connections=[1]}
IpMonitor{AddressListSize=0}
 
2011-03-15 19:29:10.307/1.296 Oracle Coherence GE 3.7.0.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2011-03-15 19:29:10.401/1.390 Oracle Coherence GE 3.7.0.0 <D5> (thread=DistributedCache:JpaDistributedCache, member=2): Service JpaDistributedCache joined the cluster with senior service member 1
Employee Timothy Gates, salary = $17736.19 
New Employee details are Timothy Gates, salary = $19509.809 
...
キャッシュ・サーバーからの応答によりログインの成功が表示され、例8-5に示すようにデータベースからの情報が取得されます。
例8-5 データベースへのログインに対するキャッシュ・サーバーの応答
2011-03-15 19:28:54.573/5.203 Oracle Coherence GE 3.7.0.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2011-03-15 19:28:54.839/5.469 Oracle Coherence GE 3.7.0.0 <D5> (thread=DistributedCache:JpaDistributedCache, member=1): Service JpaDistributedCache joined the cluster with senior service member 1
2011-03-15 19:28:54.886/5.516 Oracle Coherence GE 3.7.0.0 <Info> (thread=main, member=1): 
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  PartitionedCache{Name=JpaDistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
  )
 
Started DefaultCacheServer...
 
2011-03-15 19:29:10.261/20.891 Oracle Coherence GE 3.7.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2011-03-15 19:29:10.065, Address=130.35.99.213:8090, MachineId=49877, Location=site:us.oracle.com,machine:tpfaeffl-lap7,process:896, Role=OracleHandsonRunEmployeeExample) joined Cluster with senior member 1
2011-03-15 19:29:10.307/20.937 Oracle Coherence GE 3.7.0.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2011-03-15 19:29:10.417/21.047 Oracle Coherence GE 3.7.0.0 <D5> (thread=Cluster, member=1): Member 2 joined Service JpaDistributedCache with senior member 1
[EL Info]: 2011-03-15 19:29:13.151--ServerSession(33017287)--EclipseLink, version: Eclipse Persistence Services - 2.1.2.v20101206-r8635
[EL Info]: 2011-03-15 19:29:13.589--ServerSession(33017287)--file:/C:/home/oracle/workspace/JPA/build/classes/_JPA login successful
2011-03-15 19:29:15.073/25.703 Oracle Coherence GE 3.7.0.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2011-03-15 19:29:10.065, Address=130.35.99.213:8090, MachineId=49877, Location=site:us.oracle.com,machine:tpfaeffl-lap7,process:896, Role=OracleHandsonRunEmployeeExample) due to a peer departure; removing the member.
2011-03-15 19:29:15.073/25.703 Oracle Coherence GE 3.7.0.0 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2011-03-15 19:29:15.073/25.703 Oracle Coherence GE 3.7.0.0 <D5> (thread=Cluster, member=1): Member 2 left service JpaDistributedCache with senior member 1
2011-03-15 19:29:15.073/25.703 Oracle Coherence GE 3.7.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2011-03-15 19:29:15.073, Address=130.35.99.213:8090, MachineId=49877, Location=site:us.oracle.com,machine:tpfaeffl-lap7,process:896, Role=OracleHandsonRunEmployeeExample) left Cluster with senior member 1