Oracle® Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド 11gリリース1(11.1.1.9.0) B52028-07 |
|
![]() 前 |
![]() 次 |
この章では、ADFエンティティ・オブジェクトのイベントと機能を使用して、きわめて一般的なビジネス・ルールをOracle Application Development Framework (Oracle ADF)アプリケーション内でプログラム的に実装する方法について説明します。また、setterメソッドを使用したエンティティ行への移入など、カスタム検証コードの起動方法についても説明します。
この章には次の項が含まれます:
内蔵された宣言型検証機能を補完するため、エンティティ・オブジェクトとビュー・オブジェクトにはJavaコードを使用して、カプセル化されたビジネス・ロジックをプログラミングによって実装できるメソッド・バリデータといくつかのイベントがあります。これらの概念を、図8-1に示します。
属性レベルのメソッド・バリデータは、属性値が変更されると、検証コードをトリガーします。
エンティティ・レベルのメソッド・バリデータは、エンティティ行が検証されると、検証コードをトリガーします。
あるエンティティに対して、次の主要メソッドをカスタムJavaクラスでオーバーライドできます。
create()
: 行の作成時にデフォルト値を割り当てます。
initDefaultExpressionAttributes()
: 行の作成時、または新規行のリフレッシュ時にデフォルト値を割り当てます。
remove()
: 条件付きで削除を制限します。
isAttributeUpdateable()
: 属性を条件付きで更新可能にします。
setAttribute()
: 属性レベルのメソッド・バリデータをトリガーします。
validateEntity()
: エンティティ・レベルのメソッド・バリデータをトリガーします。
prepareForDML()
: エンティティ行が保存される前に属性値を割り当てます。
beforeCommit()
: 指定された型のすべてのエンティティ行に関連する規則を実行します。
afterCommit()
: エンティティ・オブジェクトの状態の変更に関する通知を送信します。
メソッド・バリデータは、独自のJavaコードを使用した宣言的な検証規則とGroovyスクリプト式を補完する主要な手段です。メソッド・バリデータでは、独自の検証メソッド内に記述したJavaコードが、エンティティ・オブジェクト検証サイクルにおいて適切なタイミングでトリガーされます。メソッド・バリデータにより、属性またはエンティティ全体で、様々な型の検証をコーディングできます。
それぞれがコード内の異なるメソッド名をトリガーしていれば、任意の数の属性レベルまたはエンティティレベルのメソッドを追加できます。すべての検証メソッド名はvalidate
というワードで開始する必要があります。ただし、この規則にさえ従っていれば、機能を明確に示す任意の方法で名前を付けることができます。属性レベルのバリデータでは、メソッドはエンティティ属性と同じ型の引数を1つだけ取ります。エンティティレベルのバリデータでは、メソッドは引数を取りません。メソッドはパブリックで、ブール値を返す必要があります。メソッドからfalse
が返されると、検証は失敗します。
注意: これらの規則を知っておくことは必要ですが、JDeveloperを使用してメソッド・バリデータを作成する場合、そのクラスの正しいインタフェースが作成されます。 |
実行時には、メソッド・バリデータにより、エンティティ属性がエンティティ・オブジェクト・クラスで実装されているメソッドに渡されます。
例8-1では、メソッドは大文字で始まり、NULL値で例外をスローする文字列、空の文字列、および大文字で始まらない文字列を受け取ります。
例8-1 先頭が大文字の場合に検証を行うメソッド
public boolean validateIsCapped(String text) { if (text != null && text.length() != 0 && text[0] >= 'A' && text[0] <= 'Z') { return true; } }
属性レベルのメソッド・バリデータを作成するには:
アプリケーション・ナビゲータで、目的のエンティティ・オブジェクトをダブルクリックします。
概要エディタで、「Java」ナビゲーション・タブをクリックします。
Javaページには、そのエンティティ・オブジェクトに対して現在有効なJava生成オブジェクトが表示されます。エンティティ・オブジェクトにカスタム・エンティティ・オブジェクト・クラスがない場合は、Methodバリデータの追加前に生成しておく必要があります。カスタムJavaクラスを生成するには、「編集」アイコンをクリックし、次に「エンティティ・オブジェクト・クラスの生成」を選択し、「OK」をクリックして、*.java
ファイルを生成します。
「ビジネス・ルール」ナビゲーション・タブをクリックし、「属性」ノードを展開して、検証する属性を選択します。
「新規」アイコンをクリックし、検証規則を追加します。
「ルール・タイプ」ドロップダウン・リストから、「メソッド」を選択します。
「検証ルールの追加」ダイアログに、属性レベルの検証メソッドで期待されるメソッド・シグネチャが表示されます。次のいずれかを選択できます。
エンティティ・オブジェクトのカスタムJavaクラスに、適切なシグネチャのあるメソッドがすでに存在する場合、リストに表示されます。これは「メソッドの作成と選択」チェック・ボックスの選択を解除した後に選択できます。
「メソッドの作成と選択」チェック・ボックスを選択したままにすると(図8-2を参照)、validateから始まるどのようなメソッド名でも「メソッド名」
ボックスに入力できます。「OK」をクリックすると、適切なシグネチャとともに、メソッドがエンティティ・オブジェクトのカスタムJavaクラスに追加されます。
最後に、この検証規則が失敗した場合にエンド・ユーザーに表示される、デフォルト・ロケールのエラー・メッセージのテキストを追加します。
Method Validatorを新たに追加すると、JDeveloperでは新しい検証規則を反映するように、XMLコンポーネント定義が更新されます。メソッドの作成を指定した場合、そのメソッドはエンティティ・オブジェクトのカスタムJavaクラスに追加されます。例8-2は、オーダーのOrderShippedDate
が現在月の日付であることを確認する、簡単な属性レベルの検証規則を示しています。メソッドには、対応する属性と同じ型の引数が与えられ、その条件付きのロジックはこの入力パラメータの値に基づいています。属性バリデータの起動時、属性値は対象となる新しい新しい値にはまだ設定されていません。したがって、getOrderShippedDate()
メソッドをOrderShippedDate
属性に対する属性バリデータ内でコールしても、クライアントが設定しようとしている候補値ではなく、属性の現在の値が返されます。
例8-2 簡単な属性レベルのMethod Validator
public boolean validateOrderShippedDate(Date data) { if (data != null && data.compareTo(getFirstDayOfCurrentMonth()) <= 0) { return false; } return true; }
注意: compareTo() メソッドの戻り値は、2つの日付が等しい場合はゼロ(0 )、最初の日付が次の日付より前の場合はマイナス1(-1 )、最初の日付が次の日付より後の場合はプラス1 (1 )となります。 |
エンティティ・レベルのメソッド・バリデータを作成するには:
アプリケーション・ナビゲータで、目的のエンティティ・オブジェクトをダブルクリックします。
概要エディタで、「Java」ナビゲーション・タブをクリックします。
Javaページには、そのエンティティ・オブジェクトに対して現在有効なJava生成オブジェクトが表示されます。エンティティ・オブジェクトにカスタム・エンティティ・オブジェクト・クラスがない場合は、Methodバリデータの追加前に生成しておく必要があります。カスタムJavaクラスを生成するには、「編集」アイコンをクリックし、次に「エンティティ・オブジェクト・クラスの生成」を選択し、「OK」をクリックして、*.java
ファイルを生成します。
「ビジネス・ルール」ナビゲーション・タブをクリックし、「エンティティ」ノードを選択します。
「新規」アイコンをクリックし、検証規則を追加します。
「ルール・タイプ」ドロップダウン・リストから、「メソッド」を選択します。
「検証ルールの追加」ダイアログに、エンティティレベルの検証メソッドで期待されるメソッド・シグネチャが表示されます。次のいずれかを選択できます。
エンティティ・オブジェクトのカスタムJavaクラスに、適切なシグネチャのあるメソッドがすでに存在する場合、リストに表示されます。これは「メソッドの作成と選択」チェック・ボックスの選択を解除した後に選択できます。
「メソッドの作成と選択」チェック・ボックスを選択したままにすると(図8-3を参照)、validateから始まるどのようなメソッド名でも「メソッド名」
ボックスに入力できます。「OK」をクリックすると、適切なシグネチャとともに、メソッドがエンティティ・オブジェクトのカスタムJavaクラスに追加されます。
最後に、この検証規則が失敗した場合にエンド・ユーザーに表示される、デフォルト・ロケールのエラー・メッセージのテキストを追加します。
Method Validatorを新たに追加すると、JDeveloperでは新しい検証規則を反映するように、XMLコンポーネント定義が更新されます。メソッドの作成を指定した場合、そのメソッドはエンティティ・オブジェクトのカスタムJavaクラスに追加されます。例8-3は、オーダーのOrderShippedDate
がOrderDate
より後の日付であることを確認する、簡単なエンティティ・レベル検証規則を示しています。
エンティティ・オブジェクト属性のロケール固有のUIコントロールのヒントと同様に、検証規則のエラー・メッセージは、エンティティ・オブジェクトのコンポーネント・メッセージ・バンドル・ファイルに追加されます。メッセージ・バンドル内のこれらのエンティティは、アプリケーションのデフォルトのロケールの文字列を表します。検証エラー・メッセージの翻訳バージョンについては、4.7項「リソース・バンドルの使用」で説明したUIコントロール・ヒントの翻訳と同様の手順で追加してください。
宣言的なデフォルト設定では不十分なとき、次の場合にエンティティ・オブジェクトでプログラムによるデフォルト設定を実行できます。
エンティティ行が最初に作成される場合
エンティティ行が最初に作成される場合、またはリフレッシュされてNULL値に設定される場合
エンティティ行がデータベースに保存される場合
エンティティ属性値が設定される場合
create()
メソッドは、エンティティ行の最初の作成時にデフォルト値の初期化処理を可能にするエンティティ・オブジェクト・イベントを提供します。例8-4は、Fusion Order DemoのStoreFrontモジュールにあるOrderEO
エンティティ・オブジェクトのオーバーライドされたcreateメソッドを示しています。このメソッドは、新しいオーダー・エンティティ行に、OrderDate
属性を移入する属性のsetterメソッドをコールします。
デフォルト値は、Groovy式を使用して定義することもできます。詳細は、4.10.6項「静的なデフォルト値を定義する方法」を参照してください。
例8-4 新しい行の属性値に対する、プログラムによるデフォルト設定
// In OrderEOImpl.java in Fusion Order Demo protected void create(AttributeList nameValuePair) { super.create(nameValuePair); this.setOrderDate(new Date()); }
注意: オーバーライドされたcreate() メソッド内でsetAttribute() メソッドをコールした場合、新規行はユーザー変更の行としてマークされません。このようにプログラム的に割り当てられたデフォルト値は、宣言的に割り当てられたデフォルト値のように動作します。 |
行が最初に作成されたとき、および初期化状態にリフレッシュされたときの両方で実行するプログラム的なデフォルト設定ロジックでは、initDefaultExpressionAttributes()
メソッドをオーバーライドする必要があります。
エンティティ行がNew
状態であり、そのエンティティ行に対してrefresh()
メソッドをコールした場合、REFRESH_REMOVE_NEW_ROWS
フラグまたはREFRESH_FORGET_NEW_ROWS
フラグを指定しないと、そのエンティティ行はInitialized
状態に戻ります。このプロセスの一環として、エンティティ・オブジェクトのinitDefaultExpressionAttributes()
メソッドが実行されますが、create()
メソッドは再度実行されません。
4.10.9項「トリガーが割り当てられた値との同期方法」で、主キーの属性にDBSequence
型を使用する方法を説明しています。この種の属性の値は、コミット時にデータベース・シーケンスによって取り込む必要があります。エンティティ行の作成時にユーザーが値を参照でき、この値がデータ保存時に変更されないように、順序番号を事前に割り当てる必要が生じることがあります。そのためには、例8-5
に示すように、オーバーライドされたcreate()
メソッドでoracle.jbo.server
パッケージのSequenceImplヘルパー・クラスを使用します。この例は、Fusion Order DemoのStoreFrontモジュールにあるWarehouseEO
エンティティ・オブジェクトのカスタムJavaクラスのコードを示しています。super.create()
をコールした後に、順序名と現在のトランザクション・オブジェクトを渡し、SequenceImpl
オブジェクトの新規インスタンスを作成します。続いてSequenceImpl
のgetSequenceNumber()
メソッドからの戻り値を含むsetWarehouseId()
属性のsetterメソッドをコールします。
例8-5 作成時に順序からの属性値のデフォルト設定
// In WarehouseEOImpl.java import oracle.jbo.server.SequenceImpl; // Default WarehouseId value from WAREHOUSE_SEQ sequence at entity row create time protected void create(AttributeList attributeList) { super.create(attributeList); SequenceImpl sequence = new SequenceImpl("WAREHOUSE_SEQ",getDBTransaction()); setWarehouseId(sequence.getSequenceNumber()); }
行を保存する前に、プログラムによるデフォルト値をエンティティ・オブジェクトの属性値に割り当てる場合は、prepareForDML()
メソッドをオーバーライドし、適切な属性のsetterメソッドをコールして、導出された属性値を移入します。INSERT
、UPDATE
またはDELETE
の処理中にのみ割当てを実行するには、DML_INSERT
、DML_UPDATE
、DML_DELETE
のそれぞれの整数値の定数と、このメソッドに渡されたoperation
パラメータの値を比較できます。
例8-6は、導出値を割り当てるオーバーライドされたprepareForDML()
メソッドを示しています。
例8-6 PrepareForDMLを使用した保存前の導出値の割当て
protected void prepareForDML(int operation, TransactionEvent e) { super.prepareForDML(operation, e); //Populate GL Date if (operation == DML_INSERT) { if (this.getGlDate() == null) { String glDateDefaultOption = (String)this.getInvoiceOption().getAttribute("DefaultGlDateBasis"); if ("I".equals(glDateDefaultOption)) { setAttribute(GLDATE, this.getInvoiceDate()); } else { setAttribute(GLDATE, this.getCurrentDBDate()); } } } //Populate Exchange Rate and Base Amount if null if ((operation == DML_INSERT) || (operation == DML_UPDATE)) { BigDecimal defaultExchangeRate = new BigDecimal(1.5); if ("Y".equals(this.getInvoiceOption().getAttribute("UseForeignCurTrx"))) { if (!(this.getInvoiceCurrencyCode().equals( this.getLedger().getAttribute("CurrencyCode")))) { if (this.getExchangeDate() == null) { setAttribute(EXCHANGEDATE, this.getInvoiceDate()); } if (this.getExchangeRateType() == null) { String defaultConvRateType = (String)this.getInvoiceOption().getAttribute("DefaultConvRateType"); if (defaultConvRateType != null) { setAttribute(EXCHANGERATETYPE, defaultConvRateType); } else { setAttribute(EXCHANGERATETYPE, "User"); } } if (this.getExchangeRate() == null) { setAttribute(EXCHANGERATE, defaultExchangeRate); } if ((this.getExchangeRate() != null) && (this.getInvoiceAmount() != null)) { setAttribute(INVAMOUNTFUNCCURR, (this.getExchangeRate().multiply(this.getInvoiceAmount()))); } } else { setAttribute(EXCHANGEDATE, null); setAttribute(EXCHANGERATETYPE, null); setAttribute(EXCHANGERATE, null); setAttribute(INVAMOUNTFUNCCURR, null); } } } }
他の属性値が設定されているときに、導出された属性値を割り当てるには、最後の属性のsetterメソッドにコードを追加します。例8-7は、エンティティ・オブジェクトのAssignedTo
属性に対するsetterメソッドを示しています。
例8-7 AssignedTo属性の変更に応じて割当て日を設定するメソッド
public void setAssignedTo(Number value) { setAttributeInternal(ASSIGNEDTO, value); setAssignedDate(getCurrentDateWithTime()); }
setAttributeInternal()
をコールしてAssignedTo
属性の値を設定すると、AssignedDate
属性のsetterメソッドにより、現在日時の値が設定されます。
注意: ここで説明した生成済の属性のgetterメソッドとsetterメソッドへのカスタム・コードの追加は、安全に行うことができます。JDeveloperでクラスのコードが変更された場合でも、カスタム・コードはそのまま保持されます。 |
refresh(int flag)
メソッドを行に対して使用すると、保留中のすべての変更をリフレッシュできます。refresh()
メソッドの動作は、パラメータとして渡すフラグによって決まります。この動作を制御する3つの主要なフラグの値は、Row
インタフェースの次の定数です。
REFRESH_WITH_DB_FORGET_CHANGES
は、現在のトランザクションによる行への変更を破棄し、行データがデータベースからリフレッシュされます。行が変更されたかどうかにかかわらず、現在の行はデータベースの最新データで上書きされます。
REFRESH_WITH_DB_ONLY_IF_UNCHANGED
は、unmodified
以外は、REFRESH_WITH_DB_FORGET_CHANGESと同一の機能をします。現在のトランザクションで行がすでに変更されている場合は、行はリフレッシュされません。
REFRESH_UNDO_CHANGES
は、unmodified
行に対してREFRESH_WITH_DB_FORGET_CHANGESと同一の機能をします。変更された行については、このモードは、トランザクションの開始時点での属性値でリフレッシュします。リフレッシュ操作前に現在のトランザクション内でこの行がポスト済だったが未コミットの場合、この行は修正済状態を維持します。
デフォルトでは、refresh()
を実行したNew
状態のすべてのエンティティ行がInitialized
状態の空白行に戻ります。宣言的なデフォルト値と、initDefaultExpressionAttributes()
メソッドに記述されたプログラム的なデフォルトはリセットされますが、エンティティ・オブジェクトのcreate()
メソッドは、この無効化のプロセスでは実行されません。
このデフォルトの動作は、次の2つのフラグのうちの1つと、8.4項のフラグの1つをビット単位のOR
演算子によって組み合せて変更できます。
REFRESH_REMOVE_NEW_ROWS
: リフレッシュ時に新しい行が削除されます。
REFRESH_FORGET_NEW_ROWS
: 新しい行はDead
とマークされます。
ビジネス・ロジックでSQL問合せの実行が必要とされる場合、一般的には、そのタスクの実行にはビュー・オブジェクトを使用します。検証のために実行するSQL文では、エンティティ・ベースのビュー・オブジェクトであれば、エンティティ・キャッシュ内の保留中の変更が参照されます。読取り専用ビュー・オブジェクトでは、データベースに送信されたデータのみを取得します。
エンティティ・オブジェクトは任意のアプリケーション・シナリオで再利用されるので、特定のアプリケーション・モジュールのデータ・モデル内のビュー・オブジェクト・インスタンスに直接依存してはなりません。依存する場合、他のアプリケーション・モジュールで再使用ができないという事態が発生します。
かわりに、ビュー・アクセッサを使用して、ビュー・オブジェクトに対して検証する必要があります。詳細は、10.4.1項「エンティティ・オブジェクトまたはビュー・オブジェクトのビュー・アクセッサの作成方法」を参照してください。
例8-8に示すように、検証コードはビュー・アクセッサを使用してビュー・オブジェクトにアクセスし、バインド変数を設定します。
例8-8 Methodバリデータでの検証ビュー・オブジェクトの使用
// Sample entity-level validation method public boolean validateSomethingUsingViewAccessor() { RowSet rs = getMyValidationVO(); rs.setNamedBindParameter("Name1", value1); rs.setNamedBindParameter("Name2", value2); rs.executeQuery(); if ( /* some condition */) { /* * code here returns true if the validation succeeds */ } return false; }
ベスト・プラクティス: プログラミングで行セットにアクセスする際は、必ず行セットのセカンダリ・イテレータの作成を検討してください。これにより、ビュー・オブジェクトをユーザー・インタフェース・プロジェクトのデータ・コントロールとして表示する場合に使用される、デフォルト行セットイテレータの現在の行セットに混乱が生じないようにします。作業中の行セットに対してcreateRowSetIterator() をコールし、セカンダリとして指定する行セット・イテレータを作成します。プログラミングによる反復を修了すると、コードは行セットに対してcloseRowSetIterator() をコールし、セカンダリ・イテレータをメモリーから削除する必要があります。 |
サンプル・コードで示すように、検証に使用されるビュー・オブジェクトには通常、1つ以上の名前付きのバインド変数が含まれます。この例では、setNamedBindParameter()
メソッドを使用してバインド変数を設定します。ただし、ビュー・アクセッサ定義用ページでGroovy式を使用して、JDeveloperで変数を宣言して設定することもできます。
ビュー・オブジェクトが取得するデータの種類によって、この例の「/* some condition */
」式は異なります。たとえば、ビュー・オブジェクトのSQL問合せがCOUNT()
などの集約関数を選択した場合、条件では一般的にrs.first()
メソッドを使用して最初の行にアクセスし、続いてgetAttribute()
メソッドを使用して属性値にアクセスし、そのカウントに対してデータベースが戻す結果を参照します。
問合せから0行または1行のどちらが戻されたかによって、検証が成功または失敗した場合、この条件はrs.first()
がnull
を戻したかどうかのみを検証します。rs.first()
がnull
を戻した場合、最初の行は存在しません。つまり、問合せで行は検出されていません。また、ビュー・オブジェクトから取得された1つ以上の問合せ結果に対し、検証の成否を繰り返し確認することもあります。
データベースに変更がポストされた後、コミットされる前に、変更保留中のリストの各
エンティティに対して、beforeCommit()メソッドがコールされます。これは、指定した型のすべてのエンティティ行に対して規則を適用する必要のある、ビュー・オブジェクト・ベースの検証を実行するために有効なメソッドです。
beforeCommit()
ロジックで例外ValidationException
がスローされた場合、構成中にjbo.txn.handleafterpostexc
プロパティをtrue
に設定する必要があります。これにより、フレームワークは現在のコミット・サイクルにおいて、データベースに送信済(かつコミット前)の他のエンティティ・オブジェクトのメモリー内の状態のロールバックを自動的に処理します。
エンティティ・オブジェクトまたはビュー・オブジェクトのビジネス・ロジックが独自のビュー・アクセッサ行セット上で反復処理を行い、そのビュー・アクセッサがモデルによって定義された値のリストでも使用されていない場合、セカンダリ行セット・イテレータを使用する必要はありません。たとえば、ある名前のバインド・パラメータを取るビュー・オブジェクトのAirportValidationVA
という名前のビュー・アクセッサがエンティティ・オブジェクトにある場合、GroovyスクリプトまたはJavaを使用して独自のアクセッサ行セットでの反復処理を行うことができます。例8-9に、ビュー・アクセッサ行セット上で反復処理を行うGroovyスクリプトを示します。
例8-9 Groovyスクリプトでのビュー・アクセッサの使用
AirportValidationVA.setNamedWhereClauseParam("VarTla",newValue) AirportValidationVA.executeQuery(); return AirportValidationVA.first() != null;
例8-10に、ビュー・アクセッサ行セット上で反復処理を行うJavaメソッド・バリデータを示します。
関連するエンティティ・オブジェクトから情報にアクセスするには、エンティティ・オブジェクトのカスタムJavaクラスにあるアソシエーション・アクセッサ・メソッドを使用します。アクセッサ・メソッドをコールすると、アソシエーションのカーディナリティに応じて、すべての関連するエンティティ行、またはエンティティ行のセットに簡単にアクセスできます。
アクセッサを使用して関連するエンティティ行にアクセスできます。例8-11は、Fusion Order DemoのAdvancedEntityExamples
モジュールにあるControllingPostingOrder
プロジェクトのコードを示しており、ProductsBase
エンティティ・オブジェクトのカスタムJavaクラスのオーバーライドされたpostChanges()
メソッドを示しています。この例では、getSupplier()
アソシエーション・アクセッサを使用して、製品の関連サプライヤを取得します。
例8-11 Createメソッドにおける親エンティティ行へのアクセス
// In ProducstBaseImpl.java in the ControllingPostingOrder project
// of the Fusion Order Demo Advanced Entity Examples
@Override
public void postChanges(TransactionEvent transactionEvent) {
/* If current entity is new or modified */
if (getPostState() == STATUS_NEW || getPostState() == STATUS_MODIFIED) {
/* Get the associated supplier for the product */
SuppliersImpl supplier = getSupplier()
;
/* If there is an associated product */
if (supplier != null) {
/* And if it's post-status is NEW */
if (supplier.getPostState() == STATUS_NEW) {
/* Post the supplier first, before posting this entity */
supplier.postChanges(transactionEvent);
}
}
}
super.postChanges(transactionEvent);
}
アソシエーションのカーディナリティが、複数の行が戻されるようになっている場合、アソシエーション・アクセッサを使用してエンティティ行のセットを戻すことができます。
例8-12は、Suppliers
エンティティ・オブジェクトのカスタムJavaクラスのオーバーライドされたpostChanges()
メソッドのコードを示しています。このコードでは、setSupplierId()
アソシエーション・アクセッサを使用して各行のSupplierId
属性を更新するために、getProductsBase()
アソシエーション・アクセッサを使用して、ProductsBase
行のRowSet
オブジェクトを取得します。
例8-12 アソシエーション・アクセッサを使用した関連するエンティティ行セットへのアクセス
// In SuppliersImpl.java in the ControllingPostingOrder project // of the Fusion Order Demo Advanced Entity Examples RowSet newProductsBeforePost = null; @Override public void postChanges(TransactionEvent transactionEvent) { /* Only update references if Supplier is new */ if (getPostState() == STATUS_NEW) { /* * Get a rowset of products related to this new supplier before calling super */ newProductsBeforePost = (RowSet)getProductsBase()
; } super.postChanges(transactionEvent); } ... protected void refreshFKInNewContainees() { if (newProductsBeforePost != null) { Number newSupplierId = getSupplierId().getSequenceNumber(); /* * Process the rowset of suppliers that referenced the new product prior * to posting, and update their ProdId attribute to reflect the refreshed * ProdId value that was assigned by a database sequence during posting. */ while (newProductsBeforePost.hasNext()){ ProductsBaseImpl product = (ProductsBaseImpl)newProductsBeforePost.next(); product.setSupplierId(newSupplierId)
; } closeNewProductRowSet(); } }
アプリケーションで「ADFセキュリティの構成」ウィザードを実行して、ADF認証サーブレットによるユーザーのログインとログアウトのサポートを有効にした場合、oracle.jbo.server.SessionImpl
オブジェクトでは、認証されたユーザーの名前と、そのユーザーの属するロールを取得するメソッドを使用できます。これは、クライアントがアクセス可能なoracle.jbo.Session
インタフェースの実装クラスです。
認証済ユーザーに関する情報へのアクセス方法の詳細は、30.11.4.3項「現在のユーザー名の特定方法」および30.11.4.4項「Java EEセキュリティ・ロールのメンバーシップ特定方法」を参照してください。
Oracle Fusion Webアプリケーションのセキュリティ機能の詳細は、第30章「Fusion WebアプリケーションでのADFセキュリティの有効化」を参照してください。
エンティティ属性値が現在のトランザクション内で変更されている場合、属性getterメソッドをその属性値に対してコールすると、この保留中の変更値が戻されます。変更前の元の値を取得する場合があります。getPostedAttribute()
メソッドを使用すると、エンティティ・オブジェクトのビジネス・ロジックで、エンティティ行が変更される前にデータベースから読み取った、属性の元の値を確認できます。このメソッドは属性indexを引数として取るので、JDeveloperに保管されている正しく生成された属性インデックス列挙を渡します。
現在のユーザー・セッションに関連した情報を、エンティティ・オブジェクトのビジネス・ロジックにより参照可能な方法で格納する必要がある場合、Session
オブジェクトで提供されるユーザー・データのハッシュ表を使用できます。
新規ユーザーがアプリケーション・モジュールに初めてアクセスする場合、prepareSession()
メソッドがコールされます。例8-13に示すように、アプリケーション・モジュールはprepareSession()
をオーバーライドし、ビュー・オブジェクト・インスタンスのretrieveUserInfoForAuthenticatedUser()
メソッドをコールして、認証されたユーザーに関する情報を取得します。次に、ユーザーの数値IDをユーザー・データ・ハッシュ表に保存するため、setUserIdIntoUserDataHashtable()
ヘルパー・メソッドをコールします。
例8-13 ユーザー情報の動問合せのためのprepareSession()のオーバーライド
// In the application module protected void prepareSession(Session session) { super.prepareSession(session); /* * Query the correct row in the VO based on the currently logged-in * user, using a custom method on the view object component */ getLoggedInUser().retrieveUserInfoForAuthenticatedUser(); setUserIdIntoUserDataHashtable(); }
例8-14に、ビュー・オブジェクトのretrieveUserInfoForAuthenticatedUser()
メソッドのコードを示します。これは、それ自体のEmailAddress
バインド変数を、セッションの認証されたユーザー名に設定し、executeQuery()
をコールしてUSERS
表から追加のユーザー情報を取得します。
例8-14 ユーザー詳細の追加取得のための、認証されたユーザー名へのアクセス
// In the view object's custom Java class public void retrieveUserInfoForAuthenticatedUser() { SessionImpl session = (SessionImpl)getDBTransaction().getSession(); setEmailAddress(session.getUserPrincipalName()); executeQuery(); first(); }
ビュー・オブジェクトが取得する、認証されたユーザーの情報の1つには、メソッドの結果として戻されるユーザーの数値ID番号があります。たとえば、ユーザーsking
には、数値のUserId
として300
が割り当てられています。
例8-15は、例8-13
のprepareSession()
コードで使用される、setUserIdIntoUserDataHashtable()ヘルパー・メソッドを示しています。このメソッドでは、文字列定数CURRENT_USER_ID
で指定されるキーを使用して、数値ユーザーIDをユーザー・データ・ハッシュ表に格納します。
例8-15 エンティティ・オブジェクトからのアクセスのためのユーザー・データ・ハッシュ表への情報の設定
// In the application module private void setUserIdIntoUserDataHashtable() { Integer userid = getUserIdForLoggedInUser(); Hashtable userdata = getDBTransaction().getSession().getUserData(); userdata.put(CURRENT_USER_ID, userid); }
この例の対応するエンティティ・オブジェクトでは、例8-16
のようなヘルパー・メソッドを使用して、この数値ユーザーIDを参照するようにcreate()メソッドをオーバーライドできます。オーバーライドされたメソッドでは、CreatedBy
属性を現在認証されているユーザーの数値ユーザーIDにプログラム的に設定します。
フレームワークでGroovyスクリプトを使用できる、オブジェクトにアクセス可能なadf
という名前のトップレベルのオブジェクトが用意されています。adf.userSession
オブジェクトは、ADFビジネス・コンポーネント・ユーザー・セッションへの参照を返します。これを使用してセッションに含まれているuserData
ハッシュ・マップ内の値を参照できます。
例8-17に、MyKey
という名前のuserData
ハッシュ・マップ・キーの参照に使用するGroovyスクリプトを示します。
エンティティ・オブジェクトのビジネス・ロジックにおいては、現在の日時の参照が役立つ場合があります。次のGroovyスクリプト式を使用すると、現在の日付または現在の日付と時間を参照できます。
adf.currentDate
- 現在の日付(時間を切捨て)を戻します。
adf.currentDateTime
- 現在の日付と時間を戻します。
エンティティ・オブジェクトのビジネス・ロジックでのGroovyスクリプトの使用方法の詳細は、3.6項「Groovyサポートの概要」を参照してください。
変更保留中のリストに含まれていた各
エンティティ行に対してafterCommit()メソッドがコールされ、データベースに正しく格納されます。このメソッドを使用して、コミットに関する通知を送信できます。
コミット成功時に通知を送信するもっとよい方法は、ビジネス・イベントを宣言する方法です。ビジネス・イベントの作成方法の詳細は、4.11項「ビジネス・イベントの作成」を参照してください。
remove()
メソッドは、エンティティ行削除の前に、その行に対して起動します。remove()
メソッドでは、JboException
をスローし、該当する条件を満たさない場合は行の削除を回避するよう設定できます。
たとえばremove()
メソッド内で、エンティティ・オブジェクトの状態を判断するテストを追加し、それが新規レコードの場合にのみ削除可能にすることができます。例8-18に、この方法を示します。
注意: この例は、Fusion Order DemoアぷケーションのStandaloneExamples にある、DevGuideExamples 内のConditionalDelete プロジェクトのAddressesImpl.java ファイルにあります。 |
例8-18 remove()メソッドのオーバーライドによる削除前のエンティティ状態の確認
// In the Addresses entity object custom Java class private boolean isDeleteAllowed() { byte s = this.getEntityState(); return s==STATUS_NEW; } /** * Add entity remove logic in this method. */ public void remove() { if (isDeleteAllowed()) super.remove(); else throw new JboException("Delete not allowed in this view"); }
注意: このエンティティ・オブジェクトでは、既存の構成される側の子行がある場合、マスター・エンティティ行の削除が宣言的に回避されます。このオプションは、アソシエーションの概要エディタの「関連」ページで設定します。 |
エンティティ・オブジェクト・クラス内のisAttributeUpdateable()
メソッドをオーバーライドすると、特定の属性が更新可能かどうかを、実行時に適切な条件に従ってプログラム的に判断できます。
例8-19は、現在の認証されたユーザーがスタッフ・メンバーである場合にのみPersonTypeCode
属性を更新可能にするため、エンティティ・オブジェクトによりisAttributeUpdateable()
がどのようにオーバーライドされるかを示しています。エンティティ・オブジェクトでは、このメソッドを実行する際、更新可能性の確認対象となる整数属性索引を渡します。
特定の属性に対する条件付きの更新可能性ロジックは、属性索引に基づいて、if
文またはswitch
文内に実装できます。ここでは、PERSONTYPECODE
がエンティティ・オブジェクトのカスタムJavaクラスに保持されている整数属性の索引列挙を参照します。
例8-19 属性の更新可能性の実行時の条件付きの判断
// In the entity object custom Java class public boolean isAttributeUpdateable(int index) { if (index == PERSONTYPECODE) { if (!currentUserIsStaffMember()) { return super.isAttributeUpdateable(index); } return CUSTOMER_TYPE.equals(getPersonTypeCode()) ? false : true; } return super.isAttributeUpdateable(index); }
注意: エンティティ・ベースのビュー・オブジェクトは、エンティティ・オブジェクト内でカプセル化された他の要素と同様に、この条件付きの更新可能性も継承します。この種の条件付き更新可能性ロジックを、一時ビュー・オブジェクト属性に固有の方法で実装する必要がある場合、または、ビュー・オブジェクト内の複数のエンティティ・オブジェクトのデータを含む一部の条件を適用する場合、ビュー・オブジェクトのビュー行クラス内の同じメソッドをオーバーライドすると、目的の結果が得られます。 |