Business Components for Javaには、ビジネス・ロジック層で検証ロジックを定義、実装および実行するためのフレームワークが用意されています。検証フレームワークでは、内部の実装の詳細が隠された、一貫したプログラミング・モデルが提供されます。これにより、新しいビジネス・データや更新したビジネス・データが有効であることを確認する規則に集中できます。
ビジネス・ロジック層の検証は、データベース制約とは異なります。データベース制約は、表の列にビジネス・ルールを定義する宣言です。データベース制約は、表で定義され、表定義の一部として、データベースのデータ・ディクショナリに主として保存されます。これによって、すべてのデータベース・アプリケーションに同じ規則が適用されます。
ビジネス・ロジック層の検証を使用するのは、データがビジネス・ロジック層にキャッシュされるときにデータをチェックする必要がある場合です。データベースにコミットされるときにデータを検証するにはデータベース制約を使用できます。また、データベース制約を使用すると、他のユーザーがSQL文またはプログラムでデータを変更する場合でも、データベース内のすべてのデータの有効性が常に保証されます。
ビジネス・ロジック層では、データを作成または変更する場合に検証ロジックを使用しますが、表内のデータが有効であると仮定しています。問合せにより、無効な値(たとえば、検証ロジックが適用される前に入力されたレガシー・データからの値)が含まれた結果セットが返されることがありますが、ユーザーが表に無効な値を入力することはできません。
次に、ビジネス・ロジック層で検証ロジックを定義および適用する方法を処理順に示します。宣言(XMLコード)による検証規則以外はすべて、プログラム(Javaコード)によって行われます。
ドメイン・オブジェクトは、開発者が定義するデータ型であり、検証を組み込むことができます。検証はドメイン・インスタンスが構成されるときに実行されます。エンティティ属性またはビュー属性(あるいはその両方)のデータ型としてドメインを使用できます。ドメインに検証ロジックを組み込むと、属性のデータ型としてそのドメインを指定することで同じロジックを再利用できます。たとえば、CreditCardドメインが頻繁に再利用される場合、この検証コードを検証が必要な属性ごとに書く必要はなく、ロジックを一箇所で管理できます。
クライアントのプログラミング方法に応じて、ドメイン検証はクライアントまたはビジネス・ロジック層で起動されます。たとえば、Javaクライアントは、ユーザーがフィールドから移動したときに、クライアント層でドメイン・インスタンスを作成できます。このため、無効な値を入力したユーザーにはすぐにそのことが通知されます。また、クライアントは値をJava型として渡すこともできます。この場合、ビジネス・ロジック層がその値をドメインに変換し、クライアントでインスタンス化した後でその値を検証することもできます。
ドメインのインスタンス生成後、そのインスタンスは、メソッドのパラメータとして、タイプ・セーフな方法で任意に受け渡しが可能です。
ビジネス・コンポーネント・フレームワークでは、各エンティティ・オブジェクトに固有のsetAttribute メソッド(Department.setLocationなど)を作成できます。これらのメソッドにおいて、属性を設定する前または後に検証を追加できます。適切なコーディング例としては、setAttribute メソッドをオーバーライドする場合に、setAttributeInternalをコールする前に例外をスローする検証ロジックがあります。これ以外の方法で、例外がスローされる前に属性の以前の値を取得するのは困難です。
setAttribute メソッドには、その属性値のみに適用される検証ロジックを追加できます。このロジックを何回も再利用する場合は、ロジックをドメインに組み込むことを検討してください。
属性検証ロジックを1つのメソッドに追加する場合は、setAttributeInternal属性もオーバーライドできます。検証ロジックを追加し、例外がある場合には捕捉してから、super.setAttributeInternalをコールするようにしてください。そうしないと、(例外がスローされる前に)以前の値を取得するのが困難になります。
ベースのEntityクラスにより、エンティティ・オブジェクトでオーバーライドできるvalidateEntityメソッドが提供されます。エンティティ検証は、ある行から別の行へ移動するとき起動されます。エンティティ検証は、複数の属性値を検証する場合に便利です。行全体の値が入力されるまで個別のフィールドの検証を行わない場合や、関連付けられているエンティティ・オブジェクトの値を検証する場合などです。たとえば、Salary属性を設定するとき、役職名、通貨などの別のフィールド値のチェックが必要な場合があります。また、開始日として終了日よりも前の日付を設定する必要がある場合など、日付の範囲をチェックする場合もあります。
検証規則では、検証の再利用パターンがカプセル化され、適切なパラメータ値を指定することにより、これを使用できます。エンティティ・オブジェクト・ウィザードおよびエンティティ・オブジェクト・エディタ、ならびにエンティティ属性エディタを使用して、コードを記述せずに単純な規則を定義し、適用できます。ウィザードまたはエディタを使用すると、XMLが生成され、Javaコードを再コンパイルせずに規則をカスタマイズできます。
定義済のValidatorタイプを使用することも、独自に定義することもできます。独自のカスタム検証クラスでは、より複雑な規則も実装できます。この場合、クラスをValidatorタイプとして登録し、定義済の規則と同様に適用できます。
コンポジットによって、エンティティ・オブジェクト・レベルでの親子階層の検証が提供されます。親のvalidateEntityメソッドが、検証メソッドをコールして子を検証します。たとえば、注文システムの場合、コンポジットを使用すると、明細品目がすべて有効でないかぎり注文も有効になりません。
ドメインと検証規則のどちらに検証ロジックを追加するかを決定する際には、ドメインが複数の属性で利用できるのに対して、検証規則は1つの属性またはエンティティ・オブジェクトのみに適用されるということに注意してください。たとえば、URL属性を検証する場合には、後で他の属性にドメインを使用できるため、ドメインを使用する方が便利です。しかし、フィールドにPlatinum、GoldまたはSilverのいずれかが含まれているかどうかをチェックする場合は、検証規則を使用します。これは、他の属性でこれらの値を使用する可能性が低いためです。
また、ドメインと検証規則を使用するかわりに、エンティティ・オブジェクトのJavaソース・ファイルを変更して検証ロジックを実装することも可能です。検証規則と同様、このロジックを適用できるのはエンティティ・オブジェクトまたは属性のみですが、検証規則では不可能な、複雑なロジックも追加できます。
フレームワークでは、最上位レベルのオブジェクトに規則が適用される前に、この中に含まれるオブジェクトに規則が適用されます。データベース制約および検証ロジックは、次の場合に起動されます。
データベースからデータが読み込まれる際に、ドメイン検証が起動されます。
エンティティ属性値が設定される際に、属性レベルの検証(ドメイン検証など)が起動されます。
現在の行が変わった場合、検証が明示的にコールされた場合、またはデータベースにコミットされる前に、エンティティ・レベルの検証が起動されます。
データがデータベースにポストされた場合は、ビジネス・ロジック層で検証ロジックが起動された後でデータベース制約が起動されます。または、エンティティ・レベルの検証の前に、postChangesメソッドを使用して明示的にデータベース制約を起動できます。
データがビュー・オブジェクト問合せによって要求されるとき、オブジェクト・インスタンスの作成時に行われるドメイン・コンストラクタの検証(ドメイン・コンストラクタが存在する場合)を除けば、データの読込み時には検証は行われません。
ビジネス・ロジック層によってデータベースに入力されたすべてのデータは最初に検証されているため、フレームワークではデータベースにコミットされたデータは有効であると仮定します。レガシー・データがある場合または、他のアプリケーションまたはSQL文によってデータが変更される場合は、ドメイン・コンストラクタの検証が適用されていないデータが存在する可能性があります。このドメイン検証が正常に終了しない場合は、データのフェッチ処理が失敗します。属性が1つでも検証に失敗すると、データは読み込まれません。
(たとえばJavaまたはJSPが)setAttribute メソッドをコールして属性に値を割り当てるとき、ビジネス・ロジック層は型検証を実行します。値の型を割り当てられない場合は、フレームワークが、属性の型(場合によってはドメイン)であるクラスのコンストラクタを使用して、その値を変換しようとします。変換が失敗した場合は、フレームワークによってJboExceptionがスローされます。エンティティ・オブジェクトで特定のゲッターまたはセッターをコールする場合は、Javaコンパイラが型をチェックするため実行時のチェックは不要です。
属性レベルの検証は、型検証の後に行われます。これには、setAttribute メソッドの検証ロジック、setAttributeInternalメソッドの検証ロジック、および属性レベルの検証規則があり、この順序で実行されます。
行イテレータが別の行に移動するとき、直前の行について次に該当する場合は、エンティティ・レベルの検証が行われます。
デフォルト以外のビュー行のイテレータ(2つ目のビュー行イテレータ)に対しては、setRowValidation
メソッドを使用して、エンティティ検証を無効にできます。
コミット時には、検証が必要なすべてのエンティティ・オブジェクトについてビジネス・ロジック層がエンティティ・レベルの検証を実行します。コンポジット検証を除き、無効なエンティティ・オブジェクトが検証される順序は決まっていません。新規のエンティティ・オブジェクトや変更または削除されたエンティティ・オブジェクトがデータベースにポストされるたびに、フレームワークはDML操作を実行して、データをデータベースに保存します。このとき、データベースがトリガーを起動して制約を実行します。DML操作が失敗すると、DMLExceptionがスローされます。保留中の変更内容に反するデータベースの操作を実行する場合、データをポストできますが、コミットはできません。たとえば、データベースでのソート(ORDER BYの使用)は、大容量のデータを最も速くソートできる方法です。新規作成した行を既存の行と一緒にソートする場合は、新規行をデータベースに移動する必要があります。これを行うときに、postChangesメソッドをトランザクションでコールしてデータベース検証ロジックを起動できますが、エンティティ検証は起動しないでください。エンティティ検証を起動する場合は、最初にエンティティ・オブジェクト、ビュー・オブジェクトまたはトランザクションで検証メソッドをコールします。
コンポジット関係の場合は、最初に子エンティティ・オブジェクトが検証されます(検証を必要とするもののみ)。次に、親エンティティ・オブジェクトが検証されます。子が検証される順序は決まっていません。通常、最初に変更されたエンティティ・オブジェクトが検証されますが、順序は保証されません。
詳細は、「コミット・サイクルの処理について」を参照してください。
Entity.validate
、Transaction.validate
、Row.validate
またはTransaction.commit
などのビジネス・コンポーネントAPIでメソッドをコールして、エンティティ検証を明示的に起動できます。
通常、属性検証は、setAttribute メソッド(たとえばsetDname
)により属性の値が変更されると行われます。たとえば、ユーザーが値を変更してフィールドから移動すると、setAttribute がコールされるようにGUIクライアントがコーディングされている場合は、検証が起動されます。
行の移動と同時にイテレータの現在の行を変更するようにGUIクライアントがプログラミングされている場合は、行を移動する前にエンティティ・オブジェクトの検証が起動されます。
後述のとおり、これに該当するのは、ローカル・モードでデプロイされている場合、またはリモート・モードで同期モードが即時の場合です。アプリケーションが3層環境にデプロイされており、同期モードが遅延の場合は、該当しません。
JSP、XSQLサーブレットまたはサーブレットを使用している場合、ユーザーがWebページに入力するデータは、Webページが送信されるまでは転送されません。この時点で、変更された属性値があればsetAttribute メソッドで設定され、属性検証が起動されます。ユーザーが別の行(マスター/ディテールのマスター行)を選択したために、ページが送信中の場合は、現在の行イテレータの現在の行が変わったためエンティティ・オブジェクト検証が行われます。
デプロイメントの後で、ApplicationModuleImplクラスのsetSyncModeメソッドを使用して、アプリケーション・モジュールの同期モードを設定できます。同期モードによって、setAttributeメソッドがコールされるタイミングが決まります。遅延に設定することで、ネットワーク通信量が少なくなり、アプリケーションを最適化できます。同期モードはリモート・モードでデプロイしている場合にのみ使用できます。ローカル・モードでは使用できません。
たとえば、クライアントが従業員の10の属性を設定している場合、コードではsetAttribute メソッドを10回コールすることになります。アプリケーションが即時同期モード(デフォルト)を使用している場合、アプリケーションはネットワークを10往復し、属性レベル検証がすぐに起動されます。同期モードが遅延の場合は、クライアントがビジネス・ロジック層に次にメッセージを送る(たとえば、クライアントによる現在の行の変更、postChangesまたはcommitメソッドのコール、同期メソッドのコール、検証メソッドのコールなど)まで、クライアント側の属性設定要求はバッファリングされます。
遅延同期モードを使用している場合は、即時同期モードを使用する場合とはエラーの処理方法が異なるので注意してください(たとえば、ネットワーク・エラーの処理を考慮する必要があります)。
トランザクションで検証を遅延するように指定すると、setAttributeメソッドによって検証規則が起動されません。かわりに、ロジック内のセッター・メソッドまたはsetAttributeInternalのいずれかでスローされるValidationExceptionsは、キャッシュされすぐにはスローされません。詳細は、「バンドルされた例外の使用」を参照してください。