JavaとJavaEEプログラマのブログ

JavaEEを中心にしたをソフトウェア開発についてのブログ

JavaEE6入門〜JSF2.0 デザイナーとの共同作業〜

例によって詳しくはhttp://yoshio3.com/2012/08/24/detail-of-jsf20/ を参照。

デザイナーにはXHTMLでデザインをしてもらえば、プログラマはHTMLタグにjsfc属性を追加するだけでOK。
最近増えてきたBootStrapなどのHTML5ベースのCSSフレームワークでデザインされたページはXHTMLに修正する必要がある。JSF2.2からはHTML5にも対応するので、XHTMLへの修正は不要。

URLをデザインするときは、こちらを参照のこと。
JSF 2.0 : ブックマーク可能な URL (GET リクエスト) のサポートと動的パラメータ設定

EJB3.1入門〜セキュリティ〜

JavaEEではユーザーの認証、認証されたユーザーがどのようなロールを認可されるかという設定は全てサーバーが管理する。
そのため、EJBのセキュリティ設定は、使用可能なロールの設定と、そのロールに対して、どのEJBやメソッドにアクセス許可を与えるかを設定するだけ。
使用可能なロールの設定はejb-jar.xmlに設定する。
主に使用するアノテーションは@PermitAll、@RolesAllowed、@DenyAll。どれもクラス・メソッドの両方に付加できる。
@RunAsアノテーションは、一時的にロールを切り替えるアノテーション

@Stateless

//このEJBにアクセスできるのはロールが"user","admin","employee"の場合のみ。
@RolesAllowed({"user","admin","employee"})
public class MogaEjb{


    // 全てのロールがアクセス可能なメソッド。
    // しかしBeanへのアクセスは@RolesAllowedで指定されたロールのみなので実質アクセスできるロールは"user","admin","employee"のみ。
    @PermitAll
    public boolean methodA(){
    }

    // 全てのロールに対してアクセスを拒否。
    @DenyAll
    public void methodB(){
    }
    
    // "admin"ロールのみが実行可能なメソッド。
    @RolesAllowed("admin")
    public boolean methodC(){
    }
}

@RolesAllowed({"officer","boss","ceo"})
// "officer","boss","ceo" を一時的に"admin"ロールを割り振り、アクセス許可を与える。
@RunAs("admin")
public class OtherEjb{
    
    @EJB
    @MogaEjb mogaEjb;

    
    public void methocXXX(){
        mogaEjb.methodC();//@RunAsで"admin"ロールが割り当てられるのでアクセスできる。
    }

}

@DeclareRoles 新規にロールを作る。
使用可能なロールの設定はejb-jar.xmlにまとめたほうが判りやすく、記述も楽なので使わない。


より細かくアクセス設定をしたい場合は、SessionContext.isCallerInRole() で保持しているロールを確認したり、SessionContext.getCallerPrincipal()から取得できるプリンシパル情報を利用する。

EJB3.1入門〜トランザクション〜

1メソッドを1トランザクションとして扱う。
メソッドの開始直前にトランザクションが始まり、メソッド終了直後にコミットされる。

トランザクションロールバックされるのは以下の場合。

  • メソッド内からシステム例外(RemoteExceptionかRuntimeExceptionのサブクラス)・実行時例外(RuntimeExceptionのサブクラス)が投げられた時。
  • アプリケーション例外(@javax.ejb.ApplicationExceptionアノテーションが付加された例外)が投げられたとき。
@ApplicationException(rollback = true)
public class HogeException extends Exception{
}
	

おそらく、ほとんど使用されないロールバックは以下の方法。

  • SessionContext.setRollbackOnly() を使った方法。

setRollbackOnly() を呼び出すと、呼び出したメソッドが終了した時にロールバックが行われる。

@Stateless
public class Fuga {

	@Resource
	private SessionContext ctx;

	public void methodFoo(){
	
		if(true){
			ctx.setRollbackOnly();//methodFooが終了したときにロールバック。
		}

	}

}


1メソッド内で複数トランザクションを扱いたい場合などトランザクション境界を自分でコントロールしたい場合は@TransactionManagement(TransactionManagementType.BEAN) アノテーションを使ってメソッド内でトランザクションの開始〜コミットを記述する。
おそらく、あまり使わない。

EJB3.1入門 〜リモートインターフェースなど〜

EJBにリモートインターフェースを付け加えると、EJBコンテナが実行されているサーバーの外からEJBをリモート呼び出しすることが可能になる。
リモートインターフェース等のインターフェースが無いEJBはサーバー内からのローカル呼び出しのみに対応する。
ひとつのEJBに複数のインターフェースを付加することが可能。
リモートインターフェースにはRMISOAPなどのWebService、RESTfulなどがある。

EJB3.1入門 〜EJBは三種類〜

ステートレス・セッションBean は、クライアントごとに内部状態を保持しないインスタンスEJBコンテナから提供される。
ステートフル・セッションBeanは、クライアントごとに内部状態を保持できるインスタンスEJBコンテナから提供される。
シングルトン・セッションBeanは、全てのクライアントに共通のインスタンスEJBコンテナから提供される。シングルトン・セッションBeanは内部状態を保持できる。

EJB3.1の各メソッドの同時アクセス管理はEJBコンテナが行う。そのためsynchronizedやvolatile等を使った同期管理は不要。

EJB3.1でよく使うアノテーションは以下のコードの通り。

// ステートレス・セッションBeanの指定
@Stateless
public class BussinessLogicStateless {
    
    // JPA2.0のEntityManagerを注入する。
    @PersistenceContext(unitName="databaseUnit")
    private EntityManager em;
    
    //EJB内でEJBを注入する。
    @EJB
    private OtherEJB otherEjb;

    // ejb-jar.xmlで指定されたパラメータを注入する
    @Resource(name = "currencyEntry")
    private String currency;

    // JAX-WSによるWebサービスを注入する
    @WebService(name="service", serviceName="WebServiceSpecial", targetNamespace="http://special.org")
    private SpecialWebService special; 

    // 非同期呼び出しの指定。クラスに付加すると全てのメソッドが非同期呼び出しになる。
    // java.util.Futureクラスは非同期処理の結果を受け取るクラス
    @Asynchronus
    public Future<Integer> sendOrderToWorkFlow(){
        //非同期処理を行う。
        return new AsyncResult<Integer>(status);
    }

    //Timerサービスを使うときには必須。
    @Resource
    TimerService timerService;

    public void createCustomer(){
        //timerServiceを使ってタイマを設定する。
        timerService.createCalendatTimer(birthDay, new TimerConfig(customer, true));
    }

    @Timeout
    public void sendBirthdayEmail(Timer timer){
        // timer内の情報を使ってメールを送信。
        Customer customer = (Customer)timer.getInfo();
    }
}
//ステートフル・セッションBeanの指定
@Stateful

// このBeanのインスタンスが削除されるまでのアイドル時間。
// 指定された時間が経つと@Removeアノテーションが付加されたメソッドが実行され、
// インスタンスがメモリから削除される。
@StatefulTimeout(value = 20, unit = TimeUnit.SECONDS)
public class BusinessLogcStateFul{

    // インスタンスが削除される時に実行されるメソッド
    @Remove
    public void checkout() {
        cartItems.clear();
    }
}
// このBeanよりも先に初期化したいシングルトンBeanを指定する。
@DependsOn("BeforeSingletonEjb","InitialCacheEjb")

// アプリの起動時に、このシングルトンBeanを初期化する指定。
// この指定が無ければ最初の呼び出し時に初期化される。
@Startup

// シングルトン・セッションBeanの指定。
// このBeanのインスタンスはアプリケーションに一つのみ存在するようにEJBコンテナに管理される。
@Singleton

// 全てのメソッドを共有ロック方式で各メソッドの同時呼び出しを許可する。
// @Lockが付加されていないデフォルトではLockType.WRITEで、同時呼び出しは不可。
@Lock(LockType.READ)


public class CacheEJB {


    // このメソッドは排他ロック方式でロックし、同時呼び出しを許可しない。
    // クラスに付けられた@Lockアノテーションを上書きしている。
    @Lock(LockType.WRITE)
    // 同時アクセスのタイムアウト指定。
    // 指定時間が過ぎても排他ロックが解除されない場合はConcurrentAccessTimeoutExceptionが投げられる。
    @AccessTimeout(value=20, unit=TimeUnit.SECONDS)
    public String getCacheValue(){
    }

}

// 同時実行の管理を自前で行う場合に使用。
// 同時実行の管理はEJBコンテナ管理に任せておけばよいし、それがデフォルト。
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)

JPA2.0入門 〜JPA2.0を使ったデータ操作はEntityManagerクラスのみを使う〜

データ操作はすべてEntityManagerを使って行う。

EntityManagerで主に使用するメソッドは次のとおり。

  • 検索(遅延ロードポリシーに基づいて各プロパティを初期化。検索対象が無い場合はnullを返す):find()
  • 検索(検索対象が無い場合は例外を返す):getReference()
  • 登録:persist()
  • 更新:merge()
  • 削除:remove()
  • トランザクションの取得:getTransaction()
  • Query作成:createQuery(),createNativeQuery(),createNamedQuery()
  • キャッシュを取得する:getCache()
  • エンティティをロックする(悲観的・楽観的でいくつかのモードを指定できる):lock()

あまり使わないメソッド

  • DBとエンティティを明示的に同期する:flush()
  • エンティティがEntityManagerの管理下にあるかどうか判定する:contains()
  • エンティティをEntityManagerの管理からはずす:clear()

JPA2.0入門 〜JPA2.0を使った、爆速RDB設計〜

事前準備

NetBeansをインストール。

http://netbeans.org/downloads/index.html?pagelang=ja からNetBeans7.2のJavaEEバンドル版をダウンロードしてインストール。
インストール時のウィザードでJUnitGlassFishもインストールする。

NetBeansでDBを作成

サービスタブをクリック。Java DBを右クリック→データベースの作成で使用するDBを作成する。

NetBeansJPA用のプロジェクトを作成

NetBeansのメニュー→ファイル→新規プロジェクト→MavenJavaアプリケーション
作成したプロジェクト内にあるpom.xml を以下のように修正。は適宜、最新に。NetBeansならCtrl+Spaceで補完される。
pom.xmlを修正したら、プロジェクトを右クリック→ビルドを実行し、必要なライブラリをダウンロードする。

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>        
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.2</version>
        </dependency>
            
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derbyclient</artifactId>
            <version>10.6.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derby</artifactId>
            <version>10.6.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
            <version>2.3.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

DB接続に必要なpersistence.xmlは、最初のエンティティを作るときにウィザードで名前と場所を入力する画面で、持続性ユニットの作成チェックボックスにチェックを入れると作成用のウィザードが表示される。
persistence.xml作成のウィザードでは次を選択・入力する。

  • 持続性ライブラリはEclipseLink(JPA2.0)
  • 表生成の方針
  • データベース接続ではデータベースの新規接続を選択。新規接続ウィザードではドライバはjava DB(Network)を選択し、ホスト:localhost・ポート:1527・データベース・ユーザー名・パスワードを設定する。

RDBテーブルを設計し、Entityクラスを作成する。

設計手法は次の書籍の内容をそのまま使えばOK。最も早く確実にDBテーブルを設計できる手法が解説されている。

楽々ERDレッスン (CodeZine BOOKS)

楽々ERDレッスン (CodeZine BOOKS)


Entityクラスの作成手順は楽々ERDレッスン (CodeZine BOOKS)で解説されているように、次の通りになる。
イベントとリソースを抜きだす→イベントとリソースに項目(プロパティ)を追加していく→イベントとリソースのリレーションを設定する。

NetBEansを使ったEntityクラスの作り方

  1. 作成したプロジェクトのソース・パッケージの上で右クリック→新規→エンティティ・クラス でidプロパティだけを持つEntityクラスが生成されるので、それに必要なプロパティを追加する。

それらのプロパティを設定できるコンストラクタを追加しておくと便利。

  1. 書籍の中では各テーブルに付ける識別子の項目名を「テーブル名+ID」にしているが、JPAでは全てIDにして問題無し。
  2. リレーションの設定を行う。FK(外部キー)を設定する代わりに、対象となるEntityクラスをプロパティとして設定し、アノテーションを付加する。
  3. リファクタリング→フィールドをカプセル化 で必要なsetter・getterを作成する。
  4. ビルドを実行し、エラーが出なければ完成。サービスタブをクリックして、JavaDBの中を見てみればテーブルが作成されているのが判る。

楽々ERDレッスン (CodeZine BOOKS)のP.126から説明されている「お持ち帰りご注文用紙」をJPA2.0で設計したのが以下のコード。コンストラクタ、getter/setter は省略。

@Entity
public class Customers implements Serializable {
    
    // Customers と OrdersはOrderがCustomersを持つ一方向の一対一。
    // だからCustomer側にはリレーションの設定は不要。
    
    private String name;
    
    private String tel;
}


@Entity
public class Orders implements Serializable {
    
    // CustomersとOrdersは、OrdersがCustomersを持つ一方向の一対一。
    // このリレーションは自動解決されるので、@OneToOne は無くてもOK。
    @OneToOne
    private Customers customer;
    
    // OrdersとProductsはOrdersが複数のProductsを所有する一方向の一対多。
    @OneToMany
    private List<Products> products;
    
    @Column(length=100)
    private int orderNums;
}

@Entity
public class Products implements Serializable {
    
   // OrdersとProductsはOrdersが複数のProductsを所有する一方向の一対多。
   // 一方向なので、Productsからのリレーション設定は不要。
    
    // ProductとProductCategoryは、ProductsがProductCategoryを所有する一方向の一対一。
    private ProductCategory productCategory;
    
    //長さを指定しない場合はデフォルトでVARCHAR(200)にマッピングされる。
    private String name;
    private BigDecimal price;
    private BigDecimal TaxIncludedPrice;
}

@Entity
public class ProductCategory implements Serializable {
    // ProductsとProductCategoryは、ProductsがProductCategoryを所有する一方向の一対一。
    // 一方向なので、Productsからのリレーション設定は不要。
    
    private String name;
}


リレーションの設定に使うアノテーションは次の四つだけで充分。
どのアノテーションも一方向の関係を表すのに使え、mappedBy属性を指定できるアノテーションは双方向の関係を表すのに使う。双方向の場合はどちらか一方を、もう片方の所有者として、mappedBy属性を指定する必要がある。
@OneToOne(mappedBy)
@OneToMany(mappedBy)
@ManyToOne
@ManyToMany(mappedBy)

これらのアノテーションには登録や削除をカスケードに行うように指定するためのcascae属性も指定できる。
JPA2.0で必須のアノテーションは先に挙げたリレーションの設定用と以下のコードに存在するものだけ。
これ以外のアノテーションは既存のDBをJPAにマッピングするために存在するようなものなので、覚える必要は無い。

@Entity
//テーブル名を指定するアノテーション。
@Table(name="T_CUSTOMER")
// このエンティティに関するキャッシュを無効化。キャッシュの設定はpersistence.xmlの<shared-cache-mode>属性で設定する。
@Cashable(false)
public class Customer implements Serializable {

    // 双方向の一対多。mappedByで所有者指定する。

    // cascade属性で登録時と削除時のカスケードを指定している。
    // cascadeはEntityManager APIの呼び出しを減らせる。
    // しかし不要なテーブル結合などコストのかかるDB呼び出しを引き起こす可能性があるため、
    // 明確にカスケードが必要だと判断できる時以外は使うべきでは無い。

    // fetch属性で即時フェッチを指定している。@OneToManyのデフォルトFetchはLAZY。
        @OneToMany(mappedBy = "politician", 
            cascade={CascadeType.PERSIST, CascadeType.REMOVE}, 
            fetch= FetchType.EAGER)
    // リレーションの順序を指定している。nameで降順、noteで昇順の順序をつけるように指定している。
    @OrderBy("name DESC, note ASC")
    private List<People> peoples;

    /*BlobやCLobへのマッピング  */
    @Lob
    private byte[] image;
    
    /* 日付、時刻、タイムスタンプ型へのマッピング  */
    @Temporal(TemporalType.DATE)
    private Date since;
    
   // バージョニングに使用するプロパティ。このプロパティの更新はJPAが自動で行う。
   // LongやTimestampクラスも指定することが出来る。
   // このエンティティが同時に変更される可能性がある場合は必須。
   @Version
   private Integer version;

    /* 主キーと示すためのアノテーション。ウィザードで自動生成されるので触れる必要無し */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;