この章では、アプリケーション・モジュール、ビュー・オブジェクトおよびエンティティ・オブジェクトを組み合せて使用し、ビジネス・サービスの機能全体を実装する方法について説明します。
この章の内容は次のとおりです。
アプリケーション・モジュールは、エンド・ユーザー・タスクに関連する論理作業ユニットのビジネス・サービス・メソッドおよびアクティブ・データ・モデルをカプセル化するOracle ADF Business Componentsのコンポーネントです。
この章を終了すると、図8-1に示すすべての概念に加えて、他の内容も理解できるようになります。
ビュー・オブジェクトのインスタンスをアプリケーション・モジュールで使用して、そのアクティブ・データ・モデルを定義します。
サービス・メソッドを記述して、タスク・レベルのビジネス・ロジックをカプセル化します。
クライアントがコールするメソッドを選択し、サービス・インタフェースで公開します。
複数のWebページを表示できる論理トランザクション中に、プール内のアプリケーション・モジュールを使用します。
アプリケーション・モジュールでは、データベース接続の取得と、エンティティ・オブジェクトに行われた変更の保存またはロールバックの調整を行うTransactionオブジェクトを操作します。
関連するSessionオブジェクトにより、現在のアプリケーション・ユーザーに関するランタイム情報が提供されます。
これより前の章では、ビュー・オブジェクト・インスタンスをアプリケーション・モジュールのデータ・モデルに含める方法と、クライアントからアクセス可能なビュー・オブジェクトと再使用可能なビジネス・ドメイン・レイヤー内のエンティティ・オブジェクトとの内部での連携方法の詳細を説明しました。この章では、ビジネス・サービス・メソッドをそのデータ・モデルと結合して完全なビジネス・サービスを実装する方法について説明します。
|
注意: この章の例では、第7章「エンティティ・ベースのビュー・オブジェクトを使用した更新可能なデータ・モデルの構築」と同じ基本的なSRServiceアプリケーション・モジュールを使用します。これには、図8-1に示すエンティティ・ベースのビュー・オブジェクトも含まれます。動作バージョンを体験するには、DevGuideExamplesワークスペースをhttp://otn.oracle.com/documentation/jdev/b25947_01のサンプルのダウンロード・ページからダウンロードし、ApplicationModulesプロジェクトを参照してください。 |
大規模なアプリケーションでは、通常、粒度の粗い各エンド・ユーザー・タスクをサポートするアプリケーション・モジュールを1つずつ作成します。SRDemoアプリケーションのような小規模アプリケーションでは、アプリケーション・モジュールを1つ作成すれば、アプリケーションの全機能のニーズを十分に処理できると判断する場合もあります。8.9項「アプリケーション・モジュールの粒度の決定」には、これに関する追加の説明があります。
アプリケーション・モジュールを作成する方法:
アプリケーション・モジュールの作成ウィザードを開きます。このウィザードは、「新規ギャラリ」の「Business Tier」→「ADF Business Components」カテゴリから起動できます。
ステップ1の「名前」ペインで、パッケージ名およびアプリケーション・モジュール名を指定します。
ステップ2の「データ・モデル」ページで、以前に定義したビュー・オブジェクトのインスタンスを指定し、このビュー・オブジェクト・インスタンスの名前をクライアントで認識される名前とまったく同じ名前に変更します。次に、「終了」をクリックします。
詳しい手順は、5.3項「アプリケーション・モジュールのデータ・モデルにおけるビュー・オブジェクトの使用」を参照してください。
アプリケーション・モジュールを作成すると、JDeveloperでは、その宣言的設定を表すXMLコンポーネント定義ファイルが作成され、そのパッケージの名前に対応するディレクトリに保存されます。たとえば、devguide.modelパッケージのSRServiceという名前のアプリケーション・モジュールに対しては、プロジェクトのソース・パスに./devguide/model/SRService.xmlというXMLファイルが作成されます。このXMLファイルには、ビュー・オブジェクト・インスタンスをアプリケーション・モジュールのデータ・モデルで再作成するために実行時に必要な情報が含まれています。この内容を確認するには、アプリケーション・ナビゲータでビュー・オブジェクトを選択し、構造ウィンドウで対応するソース・フォルダ内を参照して、アプリケーション・モジュールのXMLファイルを確認します。SRService.xmlノードをダブルクリックすると、このXMLがエディタで開かれ、その内容を確認できます。
|
注意: IDEレベルのビジネス・コンポーネントのJava生成設定で指定されている場合、オプションのカスタム・アプリケーション・モジュール・クラスSRServiceImpl.javaもウィザードで生成される場合があります。 |
新しいアプリケーション・モジュールを作成した後、アプリケーション・モジュール・エディタを使用してその設定を編集できます。アプリケーション・ナビゲータを右クリックして表示されるポップアップ・メニューで「編集」メニュー・オプションを選択するか、アプリケーション・モジュールをダブルクリックし、エディタを起動します。エディタの様々なパネルを開き、データ・モデル、Java生成の設定、リモート配布オプション、クライアント・インタフェース・メソッドおよびカスタム・プロパティを調整できます。
Java Database Connectivity(JDBC)URLまたはJDBCデータソース名を構成エディタの「接続タイプ」セクションで指定して、データベース接続を使用するようにアプリケーション・モジュールを構成します(図5-12を参照)。
デフォルトのYouAppModuleLocal構成では、JDBC URL接続を使用します。これは、アプリケーション・モジュールを含むプロジェクトの「プロジェクト・プロパティ」ダイアログの「ビジネス・コンポーネント」ページに設定されている名前付きの接続の定義に基づいています。図8-2は、SRDemo接続名に基づくJDBC URL接続を使用する構成で、このセクションがどのように表示されるかを示しています。SRDemoアプリケーションでのSRServiceLocalTesting構成と同様にJDBC URL接続タイプを使用する場合は、Javaが実行可能なコンテキストでアプリケーション・モジュールを使用できます。つまり、この接続タイプを使用すると、J2EEアプリケーション・サーバー内の実行に制限されません。
他に使用可能な接続タイプは、JDBCデータソースです。JDBCデータソースはアプリケーション・サーバーの構成情報の一部として定義します。定義後、アプリケーション・モジュールでは、実行時に論理名を使用してリソースを検索します。データソース接続の詳細は次の2つの部分で定義します。
アプリケーションで実行時に使用されるデータソース名を定義する標準J2EEデプロイメント・ディスクリプタを使用する論理部分。
アプリケーション・サーバー固有であり、論理データソース名を物理接続の詳細にマップする物理部分。
たとえば、例8-1は、SRDemoアプリケーションのweb.xmlファイルのresource-refタグを示しています。このタグでは、jdbc/SRDemoDSおよびjdbc/SRDemoCoreDSという名前の2つの論理データソースを定義しています。アプリケーション・モジュールにJDBCデータソース接続を使用する場合は、この論理接続名を接頭辞java:comp/envの後で参照します。したがって、SRDemoアプリケーション内のSRServiceアプリケーション・モジュールのSRServiceLocal構成を調べると、そのJDBCデータソース名フィールドの値がjava:comp/env/jdbc/SRDemoDSであることがわかります。
例8-1 web.xmlに定義されている論理データソース・リソース名
<!-- In web.xml -->
<resource-ref>
<res-ref-name>jdbc/SRDemoDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<res-ref-name>jdbc/SRDemoCoreDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
論理データソース名をweb.xmlに定義してそれらを構成で参照した後は、論理データソース名を物理接続定義にマップする別のサーバー固有の構成ファイルをターゲット・アプリケーション・サーバーに追加する必要があります。例8-2は、SRDemoアプリケーションのdata-sources.xmlファイルの内容を示しています。このファイルは、Oracle Containers for J2EE(OC4J)に固有であり、データソース接続プールおよび接続名の物理詳細を定義しています。これに類似したファイルをそれぞれのJ2EEアプリケーション・サーバー向けに用意する必要があり、このファイルはベンダーに固有の形式になります。
例8-2 アプリケーションの外部で定義されているデータソース接続の詳細
<data-sources ... >
<connection-pool name="jdev-connection-pool-SRDemo">
<connection-factory
factory-class="oracle.jdbc.pool.OracleDataSource"
password="->DataBase_User_8PQ34e6j3MDg3UcQD-BZktUAK-QpepGp"
user="srdemo" url="jdbc:oracle:thin:@localhost:1521:XE"/>
</connection-pool>
<managed-data-source name="jdev-connection-managed-SRDemo"
jndi-name="jdbc/SRDemoDS"
connection-pool-name="jdev-connection-pool-SRDemo"/>
<native-data-source name="jdev-connection-native-SRDemo"
jndi-name="jdbc/SRDemoCoreDS" ... />
</data-sources>
このプロセスの最終手順では、データソースの物理接続の詳細を論理リソース参照にマップします。OC4Jサーバーでは、例8-3に示すorion-web.xmlファイルを使用してこの手順を実行します。
例8-3 サーバー固有のファイルによる論理データソースから物理データソースへのマップ
<orion-web-app ... > <resource-ref-mapping location="jdbc/SRDemoDS" name="jdbc/SRDemoDS"/> <resource-ref-mapping location="jdbc/SRDemoCoreDS" name="jdbc/SRDemoCoreDS"/> </orion-web-app>
これらのデータソース構成の詳細を定義すると、アプリケーション・モジュールをWebアプリケーションの一部としてJ2EEアプリケーション・サーバーで使用できるようになります。
アプリケーション・モジュールのXMLコンポーネント定義の作成に加え、JDeveloperでは、SRService.xmlファイルを含むディレクトリを相対位置とするcommonという名前のサブディレクトリにあるbc4j.xcfgファイルにSRServiceLocalという名前のデフォルトの構成も追加します。アプリケーション・モジュールの構成を管理するには、アプリケーション・ナビゲータでそれを選択し、右クリックして表示されるポップアップ・メニューから「構成」を選択します。
アプリケーション・モジュールをBusiness Component Browserでテストする際は、接続構成に注意する必要があります。
これより前の章では、アプリケーション・モジュールのデータ・モデルの対話型テストにBusiness Component Browserツールがいかに有用かを学習しました。このツールは、J2EEアプリケーション・サーバーのコンテキストの外部で実行されるため、JDBCデータソースに応じた構成を使用したアプリケーション・モジュールのテストはできません。この問題は、JDBC URL接続を使用する構成を選択してアプリケーション・モジュールをテストするだけで簡単に解決できます。このためには、Business Component Browserの「接続」ダイアログにある「ビジネス・コンポーネントの構成名」ドロップダウン・リストからその構成を選択します。
Business Component Browserを使用してSRDemoアプリケーションのSRServiceアプリケーション・モジュールをテストするには、SRServiceLocalTesting構成を選択します。これは、ワークスペースのプロジェクトUnitTestsでJUnitテストに使用される構成と同じです。これらのテストもJ2EEアプリケーション・サーバーの外部で実行されるため、Business Component Browserと同じ理由から、JDBCデータソース接続タイプの構成は使用できません。
アプリケーション・モジュールでは、カスタムJavaコードを必要とせずに、そのビュー・オブジェクトのデータ・モデルをクライアントに公開できます。このため、クライアント・コードではoracle.jboパッケージのApplicationModule、ViewObject、RowSetおよびRowというインタフェースを使用して、データ・モデル内のビュー・オブジェクトを直接操作できます。しかし、ビュー・オブジェクトをクライアント・コードでプログラム的に操作できても、そのような操作が常に最適とはかぎりません。
ビュー・オブジェクトを操作するプログラム的なコードが完全なビジネス・サービス機能を実装するための論理的な特徴を備えている場合、アプリケーション・モジュールのJavaクラスでカスタム・メソッドを記述して、詳細をカプセル化する必要があります。これには次のコードが含まれます。
表示するデータを正しく問い合せるためのビュー・オブジェクト・プロパティの構成
集計結果を取得するための、ビュー・オブジェクト行の反復処理
1つ以上のビュー・オブジェクトに対する、複数ステップのプロシージャによるロジックの実行
これらの実装の詳細をアプリケーション・モジュール内で一元管理することで、次の利点が得られます。
コードの目的が、クライアントにより明確に伝わります。
必要に応じて、複数のクライアント・ページから同じコードを簡単にコールできます。
ビジネス・サービス機能全体のリグレッション・テストを簡略化できます。
クライアントに影響を与えることなく、実装を改善するオプションを使用可能にできます。
ページ内での論理ビジネス機能の宣言的な実行が可能になります。
カスタム・サービス・メソッドをアプリケーション・モジュールに追加するには、まず、そのカスタムJavaクラスを有効化する必要があります。IDEレベルの「ビジネス・コンポーネント」のJava生成設定で、アプリケーション・モジュール・クラスが自動的に生成されるように構成されている場合は、追加の手順は不要です。アプリケーション・モジュールにカスタムJavaクラスがあるかどうかが不明な場合は、図8-3に示すように、ポップアップ・メニューで「アプリケーション・モジュール・クラスに移動」オプションを選択します。このオプションでは、アプリケーション・モジュールのカスタム・クラスに簡単に移動できますが、メニューにこのオプションが表示されない場合、アプリケーション・モジュールは現在XML専用コンポーネントであることを意味します。
クラスを有効化するには、アプリケーション・モジュール・エディタを開き、「Java」ページに移動して、「アプリケーション・モジュール・クラス」の「Javaファイルの生成」チェック・ボックスを選択してから、「OK」をクリックしてウィザードを終了します。
devguide.model.SRServiceという名前のアプリケーション・モジュールでは、そのカスタムJavaファイルのデフォルト名はSRServiceImpl.javaになります。このファイルは、コンポーネントのXMLコンポーネント定義ファイルと同じ./devguide/modelディレクトリに作成されます。
アプリケーション・モジュールのJava生成オプションは、アプリケーション・モジュール・エディタの「Java」ページに後でアクセスしてもそのまま反映されています。XML定義ファイルの場合と同様、このエディタでどのような変更を行っても、カスタムJavaクラスで生成されたコードは最新の状態に保たれます。後でなんらかの理由により、カスタムJavaファイルが必要なくなった場合、「Java」ページで関連するオプションのチェック・ボックスの選択を解除すると、カスタムJavaファイルを削除できます。
デフォルトでは、アプリケーション・モジュールのJavaクラスは、最初に有効化した際、例8-4のようになります。この内容は次のとおりです。
データ・モデル内の各ビュー・オブジェクト・インスタンス用のgetterメソッド
Business Component Browserを使用してアプリケーション・モジュールのデバッグを可能にするmain()メソッド
例8-4 デフォルトで生成されるアプリケーション・モジュールのコード
package devguide.model;
import devguide.model.common.SRService;
import oracle.jbo.server.ApplicationModuleImpl;
import oracle.jbo.server.ViewLinkImpl;
import oracle.jbo.server.ViewObjectImpl;
// ---------------------------------------------------------------------
// --- File generated by Oracle ADF Business Components Design Time.
// --- Custom code may be added to this class.
// --- Warning: Do not modify method signatures of generated methods.
// ---------------------------------------------------------------------
public class SRServiceImpl extends ApplicationModuleImpl {
/** This is the default constructor (do not remove) */
public SRServiceImpl() { }
/** Sample main for debugging Business Components code using the tester */
public static void main(String[] args) {
launchTester("devguide.model", /* package name */
"SRServiceLocal" /* Configuration Name */);
}
/** Container's getter for YourViewObjectInstance1 */
public ViewObjectImpl getYourViewObjectInstance1() {
return (ViewObjectImpl)findViewObject("YourViewObjectInstance1");
}
// ... Additional ViewObjectImpl getters for each view object instance
// ... ViewLink getters for view link instances here
}
図8-4に示すように、アプリケーション・モジュール・クラスでは、カスタム・コードを追加する前にすべてのデフォルト動作を継承するようにベースADFのApplicationModuleImplクラスを拡張します。
アプリケーション・モジュールの全体的なビジネス・サービス・ロールに関する理解をこの章で深めると、Business Component Browserをテスト・インタフェースとして使用している間にアプリケーション・モジュールをJDeveloperデバッガで実行すると便利なことがわかります。テスターを使用してアプリケーション・モジュールをデバッグするには、アプリケーション・モジュールをアプリケーション・ナビゲータで選択してから、次のいずれかを実行します。
アプリケーション・ナビゲータで、アプリケーション・モジュールを右クリックし、「アプリケーション・モジュール・クラスに移動」をポップアップ・メニューから選択します。
コード・エディタを右クリックして表示されるポップアップ・メニューから「デバッグ」を選択します。
カスタム・サービス・メソッドをアプリケーション・モジュールに追加するには、アプリケーション・モジュールのカスタム・クラスに移動して、新しいメソッドのJavaコードをアプリケーション・モジュールのJava実装クラスに入力します。次のガイドラインを使用して、メソッドに適切な可視性を判断してください。メソッドをこのコンポーネントの実装内でヘルパー・メソッドとしてのみ使用する場合は、メソッドをprivateにします。アプリケーション・モジュールの最終的なサブクラスでこのメソッドを起動またはオーバーライドできるようにする場合は、メソッドをprotectedにします。クライアントによる起動を可能にする場合は、publicにする必要があります。これより前の章のSRServiceImplメソッドの例を参照してください。
|
注意: この章のSRServiceアプリケーション・モジュールでは、第6章「エンティティ・オブジェクトを使用したビジネス・ドメイン・レイヤーの作成」の最後にあるSRServiceImpl2.javaの例で示されている、強く型付けされたカスタム・エンティティ・オブジェクト・クラスを使用しています。 |
例8-5は、SRServiceアプリケーション・モジュールのSRServiceImpl.javaクラスでのprivate retrieveServiceRequestById()ヘルパー・メソッドを示しています。ここでは、関連するエンティティ定義にアクセスするためにServiceRequestImplエンティティ・オブジェクト・クラスのstatic getDefinition()メソッドが使用され、サービス・リクエストの検索に適したKeyオブジェクトを作成するためにエンティティ・オブジェクト・クラスでcreatePrimaryKey()メソッドが使用され、エンティティ行をエンティティ・キャッシュで検索するためにエンティティ定義でfindByPrimaryKey()メソッドが使用されています。このメソッドからは、強く型付けされたServiceRequestImplクラス(ServiceRequestエンティティ・オブジェクトのカスタムJavaクラス)のインスタンスが戻されます。
例8-5 カスタム・アプリケーション・モジュール・クラスのprivateヘルパー・メソッド
// In devguide.model.SRServiceImpl class
/*
* Helper method to return a ServiceRequest by Id
*/
private ServiceRequestImpl retrieveServiceRequestById(long requestId) {
EntityDefImpl svcReqDef = ServiceRequestImpl.getDefinitionObject();
Key svcReqKey =
ServiceRequestImpl.createPrimaryKey(new DBSequence(requestId));
return (ServiceRequestImpl)svcReqDef.findByPrimaryKey(getDBTransaction(),
svcReqKey);
}
例8-6は、作成する製品の名前および説明をコール元が渡すことを可能にするpublic createProduct()メソッドを示しています。ここでは、関連するエンティティ定義にアクセスするためにProductImplエンティティ・オブジェクト・クラスのgetDefinition()メソッドが使用され、トランザクションをコミットする前に渡されるパラメータ値が移入されるNameおよびDescription属性を持つProductImplエンティティ行を新規作成するためにcreateInstance2()メソッドが使用されています。
例8-6 カスタム・アプリケーション・モジュール・クラスのpublicメソッド
/*
* Create a new Product and Return its new id
*/
public long createProduct(String name, String description) {
EntityDefImpl productDef = ProductImpl.getDefinitionObject();
ProductImpl newProduct =
(ProductImpl)productDef.createInstance2(getDBTransaction(),null);
newProduct.setName(name);
newProduct.setDescription(description);
try {
getDBTransaction().commit();
}
catch (JboException ex) {
getDBTransaction().rollback();
throw ex;
}
DBSequence newIdAssigned = newProduct.getProdId();
return newIdAssigned.getSequenceNumber().longValue();
}
アプリケーション・モジュール・クラスにpublicカスタム・メソッドを追加する際に、クライアントによるそのメソッドの起動を可能にする場合、そのメソッドをアプリケーション・モジュールのクライアント・インタフェースに追加する必要があります。
アプリケーション・モジュールのカスタムJavaクラスのpublicメソッドをクライアント・インタフェースに追加するには、アプリケーション・モジュール・エディタの「クライアント・インタフェース」ページを使用します。図8-5に示すように、1つ以上の目的のメソッドを「使用可能」リストから選択し、「>」を押してメソッドを「選択済」リストに移入します。次に、「OK」をクリックしてエディタを終了します。
カスタム・サービス・メソッドをクライアント・インタフェースに公開すると、図8-6に示すように、アプリケーション・モジュールと同じ名前のJavaインタフェースが、アプリケーション・モジュールが存在するパッケージのcommonサブパッケージに作成されます。devguide.modelパッケージのSRServiceという名前のアプリケーション・モジュールでは、このインタフェースはSRServiceという名前になり、devguide.model.commonパッケージに作成されます。このインタフェースにより、oracle.jboパッケージのベースApplicationModuleインタフェースが拡張され、アプリケーション・モジュールがApplicationModuleImplクラスから継承するすべてのベース機能へのクライアント・アクセスが可能になります。
例8-7に示すように、SRServiceインタフェースには、アプリケーション・モジュールのクライアント・インタフェースに配置するように選択したすべてのメソッドのメソッド・シグネチャが含まれています。
例8-7 クライアント・インタフェース・パネルで選択されているメソッドに基づくカスタム・サービス・インタフェース
package devguide.model.common;
import oracle.jbo.ApplicationModule;
// ---------------------------------------------------------------------
// --- File generated by Oracle ADF Business Components Design Time.
// ---------------------------------------------------------------------
public interface SRService extends ApplicationModule {
long createProduct(String name, String description);
String findServiceRequestStatus(long requestId);
String findServiceRequestTechnician(long requestId);
void updateRequestStatus(long requestId, String newStatus);
}
「クライアント・インタフェース」ページの「選択済」リストのメソッドを追加または削除するたびに、対応するサービス・インタフェース・ファイルは自動的に更新されます。また、JDeveloperでは、リモート・クライアントによるアクセス用のアプリケーション・モジュールをデプロイするときに使用される関連クライアント・プロキシ・クラスも生成されます。この例のSRServiceアプリケーション・モジュールでは、クライアント・プロキシ・ファイルはSRServiceClientという名前になり、devguide.model.clientサブパッケージに作成されます。
|
注意: 新しいカスタム・メソッドをクライアント・インタフェースに追加した後で、このカスタム・メソッドがクライアント・コードからカスタム・インタフェースの使用を試みた際に、JDeveloperのコード・インサイトによる状況依存の文補完を使用できない場合は、生成されたクライアント・インタフェースの再コンパイルを試行してください。このためには、アプリケーション・モジュールをアプリケーション・ナビゲータで選択し、同じ名前のインタフェースのソース・ファイルを構造ウィンドウで選択し、「再ビルド」をポップアップ・メニューから選択します。このヒントは、ビュー・オブジェクトにかぎらず、ビュー行に追加された新しいカスタム・メソッドでも参考にしてください。 |
アプリケーション・モジュールのクライアント・インタフェースを生成することに加えて、カスタマイズ可能な他のキー・クライアント・オブジェクトを操作するための強く型付けされたクライアント・インタフェースも生成できます。アプリケーション・モジュールについての前述の説明と同じ方法で、ビュー・オブジェクト・エディタの「クライアント・インタフェース」および「カスタム行インタフェース」ページを開き、カスタム・メソッドをビュー・オブジェクト・クライアント・インタフェースおよびビュー行クライアント・インタフェースにそれぞれ追加できます。
devguide.model.queriesパッケージのServiceRequestsビュー・オブジェクトに対してカスタム・ビュー・オブジェクトのJavaクラスの生成を可能にして1つ以上のカスタム・メソッドをビュー・オブジェクト・クライアント・インタフェースに追加すると、図8-7に示すように、ServiceRequestsImplクラスおよびServiceRequestsインタフェースが生成されます。アプリケーション・モジュール・カスタム・インタフェースと同様に、commonサブパッケージに生成されます。
同様に、同じビュー・オブジェクトに対してカスタム・ビュー行のJavaクラスの生成を有効にして1つ以上のカスタム・メソッドをビュー行クライアント・インタフェースに追加すると、図8-8に示すように、ServiceRequestsRowImplクラスおよびServiceRequestsRowインタフェースが生成されます。
クライアント・インタフェースには、次のルールに従うカスタム・メソッドを追加できます。
メソッドの戻り型がvoid以外の場合、型はシリアライズ可能である必要があります。
メソッドが任意のパラメータを受け入れる場合、その型はすべてシリアライズ可能である必要があります。
メソッド・シグネチャにthrows句が含まれる場合、例外はoracle.jboパッケージのJboExceptionのインスタンスである必要があります。
つまり、そのメソッド・シグネチャ内のすべての型はjava.io.Serializableインタフェースを実装する必要があり、チェック済の例外はJboExceptionまたはそのサブクラスである必要があります。メソッドでは、アプリケーション・モジュールのクライアント・インタフェースで非表示になることなく、未チェックの例外(java.lang.RuntimeExceptionまたはそのサブクラス)をスローできます。
|
注意: アプリケーション・モジュール・クラスに追加したメソッドが「使用可能」リストに表示されない場合は、前述のいずれかのルールに違反していないかをまず確認してください。リストでの表示対象となる適切なメソッドと判断できる場合は、アプリケーション・モジュール・エディタに再移動する前に、アプリケーション・モジュール・クラスの再コンパイルを試みてください。 |
アプリケーション・モジュールのカスタム・メソッドのプライベート実装では、生成されたアクセッサ・メソッドを使用してデータ・モデル内のビュー・オブジェクト・インスタンスを簡単に参照できます。getCurrentRow()メソッドをビュー・オブジェクトでコールして、クライアント・ユーザー・インタフェースで現在行として認識されるビュー・オブジェクトの同じ現在行にアクセスできます。この便利な機能により、アプリケーション・モジュールのビジネス・サービス・メソッドの記述中には、同じアプリケーション・モジュールのデータ・モデルにある他のビュー・オブジェクト・インスタンスの現在行から値を渡すのみの場合、クライアントからのパラメータの引渡しは不要な場合があります。
たとえば、SRDemoアプリケーションのSRServiceアプリケーション・モジュールのcreateServiceRequest()メソッドではパラメータを受け入れません。このメソッドは、getGlobals().getCurrentRow()を内部でコールし、Globalsビュー・オブジェクト・インスタンスの現在行にアクセスします。次に、強く型付けされたアクセッサ・メソッドを行で使用してProblemDescriptionおよびProductId属性の値にアクセスし、この値を、新規作成されたServiceRequestエンティティ・オブジェクト行の対応する属性の値として設定します。
メソッドをアプリケーション・モジュールのクライアント・インタフェースに公開したら、それらのメソッドをクライアントから起動できます。
アプリケーション・モジュールのクライアント・インタフェースをプログラム的に操作するには、次の手順を実行します。
ApplicationModuleを、特定のクライアント・インタフェースにキャストします。
インタフェース上のいずれかのメソッドをコールします。
|
注意: この項では、説明を簡潔にするために、カスタム・アプリケーション・モジュールのインタフェースの操作のみを重視しますが、これと同じダウンキャスト方法は、ViewObjectインタフェースをServiceRequestsなどのビュー・オブジェクト・インタフェースとして使用するクライアントや、RowインタフェースをServiceRequestsRowなどのカスタム・ビュー行インタフェースとして使用するクライアントにも有効です。 |
例8-9は、この2つの手順を実行するTestClientCustomInterfaceクラスを示しています。この例は、6.8項「エンティティ・オブジェクトおよびアソシエーションのプログラム的操作」で説明した例に似ています。この項では、SRServiceImplクラス自体のmain()メソッド内からいくつかのアプリケーション・モジュール・メソッドの例をテストしました。ここでは、同じメソッドをすべてSRServiceクライアント・インタフェースを使用してクライアントからコールします。
この例の基本ロジックは次の手順に従います。
アプリケーション・モジュール・インスタンスを取得し、特定のSRServiceクライアント・インタフェースにキャストします。
|
注意: oracle.jboパッケージのデフォルトのApplicationModuleインタフェースを使用してアプリケーション・モジュールを操作している場合は、カスタム・メソッドにアクセスできません。この例では、特定のカスタム・インタフェース(SRServiceインタフェースなど)に、アプリケーション・モジュール・インスタンスをキャストします。 |
findRequestStatus()をコールし、サービス・リクエスト101のステータスを検索します。
findServiceRequestTechnician()をコールし、サービス・リクエスト101に割り当てられている技術者の名前を検索します。
updateRequestStatus()をコールし、リクエスト101のステータスを無効な値であるReopenedに更新することを試みます。
createProduct()をコールし、存在しない製品名の属性値を持つ製品の作成を試み、それに割り当てられる新しい製品IDを表示します。
例8-9 クライアントからのアプリケーション・モジュールのカスタム・インタフェースの使用
package devguide.client;
import devguide.model.common.SRService;
import oracle.jbo.JboException;
import oracle.jbo.client.Configuration;
public class TestClientCustomInterface {
public static void main(String[] args) {
String amDef = "devguide.model.SRService";
String config = "SRServiceLocal";
/*
* This is the correct way to use application custom methods
* from the client, by using the application module's automatically-
* maintained custom service interface.
*/
// 1. Acquire instance of application module, cast to client interface
SRService service =
(SRService)Configuration.createRootApplicationModule(amDef,config);
// 2. Find the status of service request 101
String status = service.findServiceRequestStatus(101);
System.out.println("Status of SR# 101 = " + status);
// 3. Find the name of the technician assigned to service request 101
String techName = service.findServiceRequestTechnician(101);
System.out.println("Technician for SR# 101 = " + techName);
try {
// 4. Try updating the status of service request 101 to an illegal value
service.updateRequestStatus(101,"Reopened");
}
catch (JboException ex) {
System.out.println("ERROR: "+ex.getMessage());
}
long id = 0;
try {
// 5. Try creating a new product with a missing required attribute
id = service.createProduct(null,"Makes Blended Fruit Drinks");
}
catch (JboException ex) {
System.out.println("ERROR: "+ex.getMessage());
}
// 6. Try creating a new product with a missing required attribute
id = service.createProduct("Smoothie Maker","Makes Blended Fruit Drinks");
System.out.println("New product created successfully with id = "+id);
Configuration.releaseRootApplicationModule(service,true);
}
}
アプリケーション・モジュールを使用するクライアント・レイヤー・コードがJ2EEアーキテクチャの同じ層にある場合、この構成は、アプリケーション・モジュールをローカル・モードで使用していることになります。ローカル・モードでは、クライアント・インタフェースはカスタム・アプリケーション・モジュールのJavaクラスによって直接実装されます。アプリケーション・モジュールをローカル・モードで使用する一般的な状況は次の場合です。
JavaServer Facesアプリケーションによる、Web層のアプリケーション・モジュールへのアクセス時
JSP/Strutsアプリケーションによる、Web層のアプリケーション・モジュールへのアクセス時
Swingアプリケーションによる、クライアント層(クライアント/サーバーの2層式)のアプリケーション・モジュールへのアクセス時
対照的に、アプリケーション・モジュールにアクセスするクライアント・レイヤー・コードがJ2EEアーキテクチャの異なる層にある場合、この構成は、アプリケーション・モジュールをリモート・モードで使用していることになります。リモート・モードでは、生成された前述のクライアント・プロキシ・クラスにより、アプリケーション・モジュール・サービス・インタフェースがクライアント側に実装され、リモートにデプロイされたアプリケーション・モジュール・サービスの操作に関する通信の詳細がすべて処理されます。リモート・モードを使用する一般的な状況は、シン・クライアントSwingアプリケーションによるリモート・アプリケーション・サーバー上のアプリケーション・モジュールへのアクセス時です。
ADF Business Components独自の機能として、クライアント・サービス・メソッドの操作に対してベスト・プラクティスのインタフェースのみを使用するアプローチにより、選択したデプロイメント・モードに関係なく、クライアント・コードを無変更で使用できます。ローカル・モードでのみ操作する場合も、サービスの操作にインタフェース・ベースのアプローチを採用することが、J2EEの開発におけるベスト・プラクティスです。アプリケーション・モジュールを使用すると、アプリケーションでこのベスト・プラクティスに従うことが非常に簡単になります。
|
注意: アプリケーション・モジュールをローカル・デプロイメント・モードとリモート・モードのどちらで使用するかにかかわらず、8.4.4項「クライアント・インタフェースのメソッド・シグネチャについて」で説明されているように、JDeveloperでの設計時には、シリアライズ可能な型をカスタム・インタフェース・メソッドで使用する必要があります。このルールに従うと、コードを変更することなく、デプロイメント・モードをローカルとリモート間で随時切り替えたり、両方を同時にサポートしたりできます。 |
oracle.jbo.clientパッケージのConfigurationクラスを使用すると、テスト用のアプリケーション・モジュールのインスタンスを非常に簡単に取得できます。このクラスは、このガイドにおいて多数のテスト・クライアント・プログラムで使用されており、アプリケーション・モジュール・サービスをJUnitリグレッション・テスト・フィクスチャの一部としてテストする章でも使用されます。しかし、このクラスは簡単に使用できるため、アプリケーション・モジュールへのアクセスが必要になるたびに、開発者がこのクラスのcreateRootApplicationModule()メソッドおよびreleaseApplicationModule()メソッドの使用を考える傾向があります。
しかし、Webアプリケーションに対しては、これよりさらに簡単な方法があります。
データをバインドするためのADF Modelレイヤーを使用してJSFまたはStruts/JSPアプリケーションを操作している場合、ViewControllerプロジェクトにADFBindingFilterというサーブレット・フィルタが構成されます。このフィルタにより、宣言的なバインディング・メタデータに基づく適切なアプリケーション・モジュール・インスタンスの自動的な取得およびリリースが調整され、サービスをデータ・コントロールとして検索できるようになります。ADF BindingContextおよびデータ・コントロールの詳細は、これより後の章で説明されます。ここでは、アプリケーション・モジュールのクライアント・インタフェースにこのBindingContextからアクセスできることを覚えておけば十分です。BindingContextは、dataという名前のリクエスト・スコープの属性を参照することで各Webページ・リクエスト中に使用できるため、バインディング・コンテキストはJSFマネージドBeanで参照できます。
たとえば、devguide.model.SRServiceアプリケーション・モジュールのカスタム・インタフェースにアクセスする場合は、例8-10に示す基本手順に従います。
JSF FacesContextにアクセスします。
#{data} EL式の値バインディングを作成します。
値バインディングを評価し、結果をBindingContextにキャストします。
データ・コントロールをBindingContextから名前で検索します。
アプリケーション・モジュールのデータ・プロバイダにデータ・コントロールからアクセスします。
アプリケーション・モジュールをそのクライアント・インタフェースにキャストします。
クライアント・インタフェースにあるいずれかのメソッドをコールします。
例8-10 JSFバッキングBeanでのアプリケーション・モジュール・クライアント・インタフェースへのアクセス
package demo.view;
import devguide.model.common.SRService;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCDataControl;
import oracle.jbo.ApplicationModule;
public class YourBackingBean {
public String commandButton_action() {
// 1. Access the FacesContext
FacesContext fc = FacesContext.getCurrentInstance();
// 2. Create value binding for the #{data} EL expression
ValueBinding vb = fc.getApplication().createValueBinding("#{data}");
// 3. Evaluate the value binding, casting the result to BindingContext
BindingContext bc = (BindingContext)vb.getValue(fc);
// 4. Find the data control by name from the binding context
DCDataControl dc = bc.findDataControl("SRServiceDataControl");
// 5. Access the application module data provider
ApplicationModule am = (ApplicationModule)dc.getDataProvider();
// 6. Cast the ApplicationModule to its client interface
SRService service = (SRService)am;
// 7. Call a method on the client interface
service.doSomethingInteresting();
return "SomeNavigationRule";
}
}
SRDemoアプリケーションには、JSFの値バインディングを使用してEL式を評価する手順をカプセル化するJSFUtilsクラスが含まれており、ドット表記法をEL式で使用すると、連続するBeanで複数のメソッド起動を連結でき、マップ内のBeanを検索できます。したがって、この2つのアイディアをまとめると、前述の複数の手順を次のような行に単一化できます。
// Access the SRService custom interface with a single EL expression
SomeService service = (SomeService)JSFUtils.resolveExpression("#{data.SRServiceDataControl.dataProvider}");
|
注意: 10.3.2項「ページの作成を開始する前にデータ・コントロール名を変更する方法」では、アプリケーション・モジュールのデータ・コントロール名の変更方法が説明されています。SRDemoアプリケーションで行ったように、前述の方法を使用して、SRServiceのデータ・コントロール名を、デフォルトのSRServiceDataControlから、アプリケーション・モジュール自体の名前に対応する短いSRServiceという名前に変更する場合、前述のコード行は次のようになります。
// Access SRService custom interface with a single EL expression
// NOTE: SRService app module data control renamed to "SRService"
SomeService service = (SomeService)JSFUtils.resolveExpression(
"#{data.SRService.dataProvider}");
|
ビューおよびコントローラ・レイヤーにStrutsおよびJSPを使用している場合は、例8-11のようなコードにより、カスタムPageControllerからBindingContextおよびアプリケーション・モジュールのカスタム・インタフェースにアクセスできます。getDataProvider()の結果は、アプリケーション・モジュール・クライアント・インタフェースに直接キャストでき、これをApplicationModuleとして事前に取得する必要はありません。
例8-11 ADFページ・コントローラでのアプリケーション・モジュール・クライアント・インタフェースへのアクセス
package demo.view;
import devguide.model.common.SRService;
import oracle.adf.controller.v2.context.LifecycleContext;
import oracle.adf.controller.v2.lifecycle.PageController;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCDataControl;
public class YourPageController extends PageController {
public void prepareModel(LifecycleContext lcContext) {
super.prepareModel(lcContext);
BindingContext bc = lcContext.getBindingContext();
DCDataControl dc = bc.findDataControl("SRServiceDataControl");
SRService service = (SRService)dc.getDataProvider();
service.doSomethingInteresting();
}
}
Swingを使用してデスクトップ・フィデリティ・アプリケーションを作成する場合は、例8-12のようなコードにより、Swingパネル内からBindingContextおよびアプリケーション・モジュールのカスタム・インタフェースにアクセスできます。
例8-12 ADF Swingパネルでのアプリケーション・モジュール・クライアント・インタフェースへのアクセス
package demo.view.panels;
import devguide.model.common.SRService;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCDataControl;
// etc.
public class YourPanel extends JPanel implements JUPanel {
// etc.
private void jButton1_actionPerformed(ActionEvent e) {
BindingContext bc = getPanelBinding().getBindingContext();
DCDataControl dc = bc.findDataControl("SRServiceDataControl");
SRService service = (SRService)dc.getDataProvider();
service.doSomethingInteresting();
}
}
ApplicationModuleImplベース・クラスには、その機能を実装する組込みメソッドが多数含まれています。付録D「ADF Business Componentsのよく使用されるメソッド」は、カスタム・アプリケーション・モジュール・クラスでよく記述、使用およびオーバーライドする最も一般的なコードのクイック・リファレンスとなっていますが、この項では、これらの組込みフレームワーク・メソッドの1つをオーバーライドしてデフォルトの動作を拡張する基本手順の理解を深めることを重視しています。
アプリケーション・モジュールの組込みフレームワーク・メソッドをオーバーライドするには、アプリケーション・モジュールのJavaクラスに移動し、JDeveloperのメイン・メニューから「ソース」→「メソッドのオーバーライド」を選択します。図8-9に示すように、「メソッドのオーバーライド」ダイアログが表示されます。スクロールバーを使用してメソッドのリストをスクロールできますが、オーバーライドするメソッドがわかっている場合は、その名前の最初の数文字を入力すると、インクリメンタル検索を実行してより速くリスト内を検索できます。
ここで、新規ユーザー・セッションでアプリケーション・モジュールのサービス・コンポーネントの操作を初めて開始したときに、アプリケーション・モジュールのprepareSession()メソッドをオーバーライドしてデフォルトの機能を拡張するとします。prepareSession(oracle.jbo.Session)メソッドの横にあるチェック・ボックスを選択し、「OK」をクリックします。
|
注意: ここではメソッドを1つのみ選択していますが、「メソッドのオーバーライド」ダイアログでは、任意の数のメソッドを選択して同時にオーバーライドできます。 |
「メソッドのオーバーライド」ダイアログを閉じると、図8-10に示すように、オーバーライドしたメソッドにカーソルが置かれた状態でコード・エディタに戻ります。メソッドには、super.prepareSession()をコールする単一行が表示されています。これは、ベース・クラスがこのメソッドに対して通常であれば実行したはずのデフォルトの動作を起動するJava構文です。カスタム・アプリケーション・モジュール・クラスでこの行の前または後にコードを追加して、デフォルトの機能の前または後のデフォルトの動作を拡張できます。
また、ベース・クラスのメソッドをオーバーライドすると、コード・エディタの左マージンに小さな上向きの矢印アイコンが表示されます。これは、このメソッドがインタフェースまたはベース・クラスに関連付けられていることを示しています。図に示すようにマウスをアイコンの上に動かすと、ベース・クラスのメソッドをオーバーライドできる正しいシグネチャがこのメソッドにあるという正のフィードバックが表示されます。
このメソッドは「メソッドのオーバーライド」ダイアログで生成されましたが、オーバーライドしたメソッド名の入力をメモリーから開始する場合は、オーバーライドするベース・クラス・メソッドと完全に同じシグネチャが必要です。オーバーライドしたはずのメソッドのスペルを間違えた場合や、引数または戻り値の数または型が正しくない場合は、コンパイル・エラーは発生しませんが、目的のベース・クラス・メソッドはオーバーライドされません。正のフィードバックにより、メソッド名の指定が完全に正しいことが明確になります。スーパークラスのコール時に何が行われているかを再確認するためにベース・クラスに迅速に移動するには、マージンにあるオーバーライド・アイコンを右クリックして表示されるポップアップ・メニューで「オーバーライドされたメソッドに移動」を選択します。
|
注意: 設計時に表示される前述のメソッドのオーバーライドに対する確認に加えて、自身のスーパークラスのオーバーライドを目的とするクラス内のメソッドの直前には、JDK 5.0の@Override注釈も追加できます。この注釈により、スーパークラスのメソッドのシグネチャと一致しない場合は、コンパイル時にエラーが生成されます。 |
prepareSession()メソッドは、新規ユーザー・セッションによるアプリケーション・モジュールの初回使用時にアプリケーション・モジュールによって起動されるため、アプリケーション・モジュールを使用する各新規ユーザーに固有の設定タスクを実行するようにカスタム・アプリケーション・モジュール・クラスでオーバーライドすると便利です。例8-13は、devguide.model.SRServiceImplクラスのオーバーライドされたprepareSession()メソッドを示しています。このメソッドにより、findLoggedInUserByEmailInStaffList()ヘルパー・メソッドが起動され、StaffListビュー・オブジェクト・インスタンスの初期化と、現在ログインしているユーザーに対応する行の表示が行われます。
このヘルパー・メソッドによって行われる処理は次のとおりです。
super.prepareSession()のコールによる、デフォルト処理の実行
生成されたgetStaffList() getterメソッドによる、StaffListビュー・オブジェクト・インスタンスへのアクセス
getUserPrincipalName()メソッドのコールによる、現在認証されているユーザーの名前の取得
|
注意: アプリケーションでJ2EEセキュリティを有効化する方法を30.4項「コンテナ管理のセキュリティを使用するためのADF Business Componentsアプリケーションの構成」で学習するまでは、次のサンプルのgetUserPrincipalName() APIにより、認証されたユーザーの名前ではなくnullが戻されます。このため、次の例には、固定の電子メールIDであるskingを割り当てるフォールバック・コードがテスト目的で含まれています。 |
CurrentUserという名前のバインド変数の定義(currentUserNameメンバー変数をデフォルト値として使用)
追加のWHERE句の設定による、電子メールでの現在のユーザーの行の検索
問合せの実行による、現在のユーザーのStaffList行の取得
prepareSession()メソッドをこの方法でオーバーライドした後、Business Component Browserを使用してSRServiceアプリケーション・モジュールをテストすると、Steven King(email = 'sking')に対応する単一行がStaffListビュー・オブジェクト・インスタンスに表示されます。
例8-13 StaffListビュー・オブジェクト・インスタンスの初期化による現在のユーザーに関する情報の表示
// In devguide.model.SRServiceImpl class
protected void prepareSession(Session session) {
// 1. Call the superclass to perform the default processing
super.prepareSession(session);
findLoggedInUserByEmailInStaffList();
}
private void findLoggedInUserByEmailInStaffList() {
// 2. Access the StaffList vo instance using the generated getter method
ViewObject staffList = getStaffList();
// 3. Get the name of the currently authenticated user
String currentUserName = getUserPrincipalName();
/*
* Until later when we learn how to integrate J2EE security,
* this API will return null. For testing, we can default it
* to the email of one of the staff members like "sking".
*/
if (currentUserName == null) {
currentUserName = "sking";
}
/*
* We can't use a simple findByKey since the key for the
* StaffList view object is the numerical userid of the staff member
* and we want to find the user by their email address. We could build
* an "EMAIL = :CurrentUser" where clause directly into the view object
* at design time, but here let's illustrate doing it dynamically to
* see this alternative.
*/
// 4. Define named bind variable, with currentUserName as default value
staffList.defineNamedWhereClauseParam("CurrentUser", // bindvar name
currentUserName, // default value
null);
// 5. Set an additional WHERE clause to find the current user's row by email
staffList.setWhereClause("EMAIL = :CurrentUser");
// 6. Execute the query to retrieve the StaffList row for the current user
staffList.executeQuery();
/*
* If the view object needs to be also used during this session
* without the additional where clause, you would use
* setWhereClause(null) and removeNamedWhereClauseParam("CurrentUser") to
* leave the view object instance back in it's original state.
*/
}
ビジネス・サービスのデータ・モデルおよびサービス・インタフェースはチームの主要な資産であるため、多くの場合、UMLモデルを使用して視覚化すると便利です。JDeveloperでは、ユーザーおよびその同僚が参照できるアプリケーション・モジュール用のダイアグラムを簡単に作成できます。
「新規ギャラリ」の「Business Tier」→「ADF Business Components」カテゴリからビジネス・コンポーネント・ダイアグラムの作成ダイアログを開きます。
このダイアログでは、ダイアグラム名と、ダイアグラムの作成先のパッケージ名を入力するよう求められます。ダイアグラム名(SRService Data Modelなど)およびパッケージ名(devguide.model.designなど)を入力します。
「OK」をクリックすると、空のダイアグラムが作成され、ダイアグラマが開きます。
既存のアプリケーション・モジュールをダイアグラムに追加するには、追加するすべてのモジュールをアプリケーション・ナビゲータで選択してダイアグラム画面にドロップします。
プロパティ・インスペクタを次の目的で使用します。
パッケージ名の非表示化
フォントの変更
グリッドおよび改ページの非表示化
ビュー・リンク上のロール名(マスター/ディテール)の非表示化
これらの手順の完了後、ダイアグラムは図8-11のようになります。
ビジネス・コンポーネント・ダイアグラムを作成すると、ダイアグラムが格納されているパッケージ名と一致するプロジェクトのモデル・パスのサブディレクトリに、ダイアグラムを示すXMLファイルが作成されます。前述のBusiness Domain Objectsダイアグラムの場合、一致する*.oxd_bc4jファイルがモデル・パスの./devguide/model/designサブディレクトリに作成されます。デフォルトでは、アプリケーション・ナビゲータによってプロジェクト・コンテンツ・パスの表示が統一され、ソース・パスのADFコンポーネントおよびJavaファイルがプロジェクト・モデル・パスのUMLモデル・アーティファクトと同じパッケージ・ツリーに表示されます。アプリケーション・ナビゲータの「ディレクトリの切替え」ツールバー・アイコンを使用すると、統一されたディレクトリ・ビューと個々のプロジェクト・コンテンツ・パス・フォルダを切り替えることができます。
また、アプリケーション・モジュールの編集、表示オプションの制御、メソッド名のフィルタ処理、関連するオブジェクトやファイルの表示、アプリケーションの公開、Business Component Browserの起動など、多数のタスクをダイアグラム上で直接実行できます。
ビジネス・コンポーネントのUMLダイアグラムは、アプリケーション・モジュールをダイアグラムにドロップした時点の状態を示す単なる静的な図ではありません。むしろ、UMLダイアグラムは、現在のコンポーネント定義をUMLベースでレンダリングした図であるため、常に現在の状況を示しています。UMLダイアグラムは、視覚化を可能にするのみならず、視覚的なナビゲーションおよび編集ツールでもあります。ダイアグラムを右クリックして表示されるポップアップ・メニューから「プロパティ」を選択(またはダブルクリック)すると、任意のアプリケーション・モジュールのアプリケーション・モジュール・エディタを起動できます。また、ビュー・オブジェクト・インスタンス名の変更、ビュー・オブジェクト定義をデータ・モデルにドロップすることによる新しいビュー・オブジェクト・インスタンスの作成、[Del]キーを押すことによるビュー・オブジェクト・インスタンスの削除など、いくつかのアプリケーション・モジュール編集タスクもダイアグラム上で直接実行できます。
表示オプションを制御するには、アプリケーション・モジュールをダイアグラムで選択した後で、プロパティ・インスペクタを使用します。「Display」カテゴリで、プロパティを次のように切り替えます。
ステレオタイプの表示: オブジェクトのタイプを表示(<<アプリケーション・モジュール>>など)
操作の表示: サービス・メソッドを表示
パッケージを表示: パッケージ名を表示
|
注意: 操作という用語は、メソッドを表す総称的なUML名です。 |
「Operations」カテゴリでは、通常、ダイアグラムに求められる詳細のレベルに応じて次のプロパティを変更します。
メソッド・パラメータの表示
戻り型の表示
可視性の表示(「public」、「private」など)
右クリックして表示されるポップアップ・メニューでは、「表示モード」で次のオプションも選択できます。
標準: サービス操作を表示
拡張済: 操作およびデータ・モデルを表示(デフォルト)
圧縮: アイコンおよび名前のみを表示
デフォルトでは、アプリケーション・モジュールの操作を表示すると、ダイアグラムにすべてのメソッドが表示されます。オーバーライドされたフレームワーク・メソッドとして認識されるメソッドは、すべて「Framework」操作カテゴリに表示されます。他のメソッドは、「Business」メソッド・カテゴリに表示されます。
「対象外の操作フィルタ」プロパティは、ダイアグラムでの表示が不要なメソッドのフィルタ処理に使用できる正規表現です。たとえば、「対象外の操作フィルタ」プロパティを次のように設定します。
findLoggedInUser.*|retrieveService.*|get.*
この場合、次のアプリケーション・モジュール・メソッドをすべてフィルタ処理できます。
findLoggedInUserByEmailInStaff
retrieveServiceRequestById
生成されたビュー・オブジェクトのgetterメソッド全般
ダイアグラムでアプリケーション・モジュールを選択した後、またはそのデータ・モデル内の個々のビュー・オブジェクト・インスタンスのセットを選択した後、右クリックして表示されるポップアップ・メニューから「表示」→「関連する要素」を選択すると、関連するコンポーネントの定義をダイアグラムに表示できます。同様に、「表示」→「実装ファイル」を選択すると、アプリケーション・モジュールを実装するファイルがダイアグラムに追加されます。求められる詳細のレベルがダイアグラムに追加されるまで、表示されている追加ダイアグラム要素に対して前述のオプションを繰り返し使用できます。
|
注意: コンポーネントをダイアグラムから削除すると、その表示のダイアグラム画面からの削除のみが行われます。コンポーネントおよびクラスは、ファイル・システムおよびアプリケーション・ナビゲータに残ります。 |
図8-12は、devguide.model.SRServiceアプリケーション・モジュールの実装ファイルを追加した場合の画面を示しています。この図では、SRServiceImplクラスに関連する要素と、SRServiceアプリケーション・モジュールとSRServiceImplクラスの間の依存性を示す追加の線が表示されています。生成されたSRServiceクライアント・インタフェース(前述の手順で使用)に注目してください。
エンド・ユーザーとアプリケーションとの対話中に、次のような状況が発生する場合があります。
同じページを複数回表示する場合に、迅速なレスポンスを期待
完了までに多数のページを表示する必要がある論理作業ユニットを実行
未保存の保留中の変更内容の部分的なロールバックの実行を要求
サーバー・ファームのアプリケーション・サーバー障害による、保存前の保留中の変更への不可抗力的な被害
この項では、これらの状況に対処するスケーラブルで高パフォーマンスのアプリケーションの実装を簡略化する、アプリケーション・モジュール・プーリング機能および状態管理機能を簡潔に概説します。
アプリケーション・モジュールをそのビジネス・サービスとして利用するアプリケーションを作成すると、そのアプリケーションでは自動アプリケーション・モジュール・プーリング機能を使用できます。この機能では、アプリケーションに対するエンド・ユーザーの負荷(ロード)の日中の変化に応じて増減するアプリケーション・モジュール・インスタンスの構成可能なセットを管理します。アプリケーション・ユーザー・インタフェースとのエンド・ユーザーの対話に特有の思考時間の性質により、プール内のアプリケーション・モジュール・インスタンスの数は、システムを使用しているアクティブ・ユーザーの合計数より少なくなる場合があります。
図8-13に示すように、あるエンド・ユーザーがアプリケーションの複数ページを表示して論理タスクを実行する場合、各ページ・リクエストに対し、プール内のアプリケーション・モジュール・インスタンスがその1リクエストの存続時間中にプールから自動的に取得されます。リクエストの最後に、インスタンスはプールに自動的に戻され、別のユーザー・セッションで使用可能になります。エンド・ユーザーの作業をアプリケーション・サーバーの障害から保護するために、アプリケーション・モジュールでは、そのエンティティ・キャッシュ内の保留中の変更セットを示すXMLスナップショットを保存することで、その変更セットを永続ストアに格納する機能をサポートしています。スケーラビリティ上の理由から、この状態スナップショットは通常、アプリケーション・データを含むデータベース・スキーマとは別の状態管理スキーマに保存されます。
このプーリング・アルゴリズムによって調整可能な最適化が行われ、特定の数のアプリケーション・モジュール・インスタンスは、それをプールに戻した最終ユーザー・セッションに永続的な状態を維持しようとします。最適化は絶対的な保証ではありませんが、最適化による利点を得られる場合、システム・ロードで許容されるかぎり、ユーザーはプールの同じアプリケーション・モジュール・インスタンスの操作を続行します。ロードが高すぎる場合、このプーリング・アルゴリズムでは、プール内の使用可能なインスタンスを使用してユーザーのリクエストが処理されます。そして、最終インスタンスがオフの状態でアプリケーション・モジュールの新しいインスタンスを続行できるように、論理作業ユニットのデハイドレート済スナップショットを永続ストアからリハイドレートします。エンド・ユーザーは、自分が行った変更をコミットまたはロールバックするまで、この方法で作業を続けます。
アプリケーション・モジュールはこれらの機能を使用し、完全にステートレスなアプリケーションに近い実行時パフォーマンスを実現するアーキテクチャにおいて、複数ページのワークフローを簡単に処理できる、生産性の高いステートフルな開発パラダイムを実現します。これらのアプリケーション・モジュール機能の詳細は第28章「アプリケーション・モジュールの状態管理」を、調整方法は第29章「アプリケーション・モジュール・プーリングの理解」を参照してください。
|
注意: このアプリケーション・モジュール・プーリングおよび状態管理の機能は、デスクトップ・フィデリティのシン・クライアントSwingアプリケーションおよびWebスタイルのユーザー・インタフェースにも使用できます。 |
状態管理機能の内容を簡単に試験的に確認するには、devguide.model.SRServiceアプリケーション・モジュールでBusiness Component Browserを起動し、次の手順を実行します。
OpenProblemsAndAssigneesビュー・オブジェクト・インスタンスをダブルクリックしてそのデータを問い合せます。
数行の「ステータス」および「割当て先」という属性の現在の値をメモします。
これらの行の「ステータス」および「割当て先」を別の値に更新します。ただし、変更はコミットしないでください。
Business Component Browserのメイン・メニューから「ファイル」→「トランザクション状態の保存」を選択します。
「受動化されたトランザクション状態」ダイアログが開き、トランザクションID番号が表示されます。この番号をメモします。
Business Component Browserを終了してから再起動します。
Business Component Browserを完全に終了します。
Business Component Browserを再起動し、OpenProblemsAndAssigneesビュー・オブジェクト・インスタンスをダブルクリックしてそのデータを問い合せます。
データは変更されていません。データから問い合せたデータは、データベースの現在の状態を示し、前述の変更は反映されていません。
Business Component Browserのメイン・メニューから「ファイル」→「トランザクション状態のリストア」を選択し、手順4でメモしたトランザクションIDを入力します。
この時点で、保留中の変更セットが、変更した行に再反映されます。ここでトランザクションをコミットすると、変更内容はデータベースに永続的に保存されます。
アプリケーション・モジュールの開発者に共通する問題は、開発するアプリケーション・モジュールの大きさについてです。つまり、大規模なアプリケーション・モジュールを1つ作成してエンタープライズ・アプリケーションのデータ・モデル全体を含めるか、より小規模なアプリケーション・モジュールを多数作成するか、という問題です。この解答は、状況によって異なります。この項では、開発する独自のアプリケーションに対してこの問題への解答を得るためのヒントをいくつか提供します。
一般に、アプリケーション・モジュールのサイズは、そのモジュールでの対応が想定される特定のユースケースを十分にサポートできる大きさにする必要があります。次に説明するネスト機能を使用すると、粒度の細かい複数のアプリケーション・モジュール・コンポーネントからのアセンブルが可能になります。複雑なビジネス・アプリケーションのユースケースは通常は1つではないため、ADFで実装される複雑なビジネス・アプリケーションは一般に単一アプリケーション・モジュールになりません。
SRDemoアプリケーションなどの例では、実装する1つの主要なユースケースのみでユーザーによるサービス・リクエストの管理が可能になります。一方で、技術者のスキルを管理するアプリケーションの機能は、別のバックエンドのユースケースと考えることもでき、この考え方も正解です。しかし、実際には、デモのこのようなモデリングは、2つのビュー・オブジェクト・インスタンスを内部に持つ別のアプリケーション・モジュールがあることを示唆しています。このため、SRDemoの開発者は、簡略化を図るために、この小規模なサンプル・アプリケーションのすべてを単一アプリケーション・モジュールに含めることが可能になっています。
アプリケーション開発の早期分析段階では、アーキテクトと設計者は通常、UMLユースケース手法を使用して、作成中のシステムでサポートが必要な各種のエンド・ユーザー機能の概要を反復的に調整します。
この設計段階中に識別されるエンド・ユーザーの高レベルな各ユースケースでは、一般に次の2種類の論理出力が識別されます。
対象となるドメイン・ビジネス・オブジェクト
ユースケースに関連するコア・ビジネス・データを検討します。
必要なビジネス・データのユーザー指向ビュー
ユースケースをサポートするために必要な列サブセット、フィルタ処理された行セット、ソート方法、グループ化方法などを検討します。
ユースケースに関連するドメイン・オブジェクトを識別すると、ビジネス・ドメイン・レイヤー内のどのエンティティ・オブジェクトがユースケースに関連するかを把握する際に便利です。必要なビジネス・データのユーザー指向ビューは、ビュー・オブジェクトとして取得された適切なSQL問合せを開発者が定義して、エンド・ユーザー用のデータを期待どおりに取得する際に便利です。これには、パフォーマンスを最大化するために、ユースケースのサポートに必要な最低限の詳細の取得も含まれます。これまでの説明で、ビュー・オブジェクト問合せを利用してデータを形成する方法のみならず、ビュー・リンクを使用してデータ・モデルに自然なマスター/ディテール階層を設定し、期待どおりのエンド・ユーザー体験をユーザーに提供してユースケースを実現する方法も、すでに学習しました。
アプリケーション・モジュールは、当該のユースケースに必要な再使用可能なビュー・オブジェクトのインスタンスを含む作業ユニット・コンテナです。これらのオブジェクトは、ユースケースで表示または変更している情報を含む再使用可能なビジネス・ドメイン・レイヤー内の基礎となるエンティティ・オブジェクトに、メタデータを通じて関連付けられています。
ユースケースはモジュール化機能に対応しています。特定の高レベルな機能では、複数のビジネス・ワークフローに共通なサブ機能を再使用する場合があります。アプリケーション・モジュールでは、他のアプリケーション・モジュールのインスタンスを使用してアセンブルする複合アプリケーション・モジュールを作成することで、この自然なモジュール性を模倣するソフトウェア・コンポーネントを作成する機能をサポートしています。アプリケーション・モジュールのインスタンスを別のアプリケーションにネストするときは、ビュー・オブジェクトをそのデータ・モデルに集約するのみならず、そこで定義されているカスタム・サービス・メソッドも集約します。あるアプリケーション・モジュールのインスタンスを別のアプリケーション内でネストまたは再使用するこの機能は、通常、SRDemoアプリケーションのような単純な例の中心的な要素ではありませんが、大規模で実用的なアプリケーション・システムの実装では、Oracle ADFのADF Business Componentsレイヤーにおける最も強力な設計要素の1つとなります。
アプリケーション・モジュールによりエンド・ユーザーのユースケースまたはワークフローに示される基本ロジックを使用すると、一部の共有のモジュール化ユースケースで必要なデータを提供するアプリケーション・モジュールを作成でき、より複雑なユースケースをサポートするように設計されている、より複雑な別のアプリケーション・モジュール内でそれらのアプリケーション・モジュールを再使用できます。たとえば、アプリケーション・モジュールSRServiceおよびProductMaintenaceServiceを作成した後に、この両方のサービスを新しいCompositeServiceの不可欠な部分として使用するアプリケーションの作成が必要になったとします。図8-14は、このCompositeServiceがJDeveloperのビジネス・コンポーネント・ダイアグラムでどのように表示されるかを示しています。この図に示すように、CompositeServiceなどのアプリケーション・モジュールには、ビュー・オブジェクト・インスタンスとアプリケーション・モジュール・インスタンスの両方を含めることができます。
ネストされたアプリケーション・モジュールをアプリケーションで利用する場合は、10.3.7項「データ・コントロール・パレットでのネストされたアプリケーション・モジュールの表示」を必ず参照してください。また、これらのモジュールを含むデータ・バインディングの実行時によく発生する問題を回避してください。
実行時に、アプリケーションでメイン・アプリケーション・モジュール(つまり、ルート・アプリケーション・モジュール)を操作します。どのアプリケーション・モジュールもルート・アプリケーション・モジュールとして使用できますが、実際には、単純なCRUDアプリケーションを作成している場合を除き、より複雑なエンド・ユーザーのユースケースに対応するアプリケーション・モジュールがルートとして使用されます。ルート・アプリケーション・モジュールに別のアプリケーション・モジュールがネストされている場合、そのモジュールはすべてルート・アプリケーション・モジュールのトランザクションに関与し、同じデータベース接続および単一のエンティティ・キャッシュ・セットを共有します。この共有は、ルート・アプリケーション・モジュールおよびそのTransactionオブジェクトによって自動的に処理されます。
実行時に、アプリケーションで使用されるトップレベルの各アプリケーション・モジュールによって、そのモジュール用に作成されたアプリケーション・モジュール・プールが取得されます。より高度な、多数のビジネス機能を含む大規模アプリケーションを作成するカスタマ(Oracle Applicationsなど)では、コンテナ・アプリケーション・モジュールの汎用プールをより効率よく使用するカスタム・コードを一般に記述しており、数百ものアプリケーション・モジュール・プールが生成されないようにしています。これらのカスタマでは、起動が必要なカスタマ・ワークフローに基づいて、汎用アプリケーション・モジュール(通常は、独自のビュー・オブジェクト・インスタンスを持たないアプリケーション・モジュールか、独自のビュー・オブジェクト・インスタンスが設計時に定義されている、ネストされたアプリケーション・モジュール)を取得するコードが記述されています。また、createApplicationModule() APIをこの汎用アプリケーション・モジュールでプログラムにより使用して、適切なユースケースに基づいたアプリケーション・モジュールのインスタンスを実行時に動的にネストします。ユーザーの処理が終了すると、その動的にネストされたアプリケーション・モジュール・インスタンスでremove()がコールされ、汎用アプリケーション・モジュールが再び空のまま保持され、実現が必要な任意のユースケースで別のエンド・ユーザーが使用できるようになります。