その他のヒント、コツ、避けるべきこと
このセクションは以下のトピックで構成されます。
• アクセス許可の使い方
• 経験に基づいた方法: 操作/属性/コンポーネントごとに 1 つのバリデータ
• WTReferences をインフレートしないこと
• Null 値の処理
• @Override アノテーションの使用
• UIValidationCriteria.toString()
アクセス許可の使い方
UIValidationCriteria には、アクセス許可の保存に使用できる属性があります。アクセス許可は、1 つのバリデータまたはフィルタによって読み込まれ、後続のバリデータまたはフィルタで使用されます。たとえば、actionA、actionB、actionC があり、すべて操作モデルが同じで、ユーザーが現在のコンテナで修正アクセス許可を持っているかどうかを確かめる必要があるとします。actionA のバリデータまたはフィルタを最初に呼び出した場合、AccessControlManager にアクセス許可を照会し、それを UIValidationCriteria に保存します。そうすれば、actionB と actionC のバリデータまたはフィルタは、同じ照会をもう一度実行する必要がありません。
通常、バリデータまたはフィルタでアクセス許可を確認する必要がある場合は、以下の手順を実行します。
• 新しい UIValidationCriteria.getCachedAccessPermissions() メソッドを呼び出して、アクセス許可がすでに UIValidationCriteria に保存されているかどうかを確認します。
• getCachedAccessPermissions() が null 以外の値を返した場合は、そのアクセス許可を検証チェックで使用できます。
• getCachedAccessPermissions() が null を返した場合は、AccessControlManager を照会し、必要なアクセス許可を取得します。次に setCachedAccessPermissions() メソッドを呼び出して、そのアクセス許可を後続のバリデータ用に UIValidationCriteria に保存します。
UIValidationCriteira の cachedAccessPermissions 属性の目的は、AccessControlManager.getPermissions() の結果を保存することです。
このため、バリデータまたはフィルタのコードは以下のように記述する必要があります。
// check to see if the access permissions have already been
calculated...
WTKeyedHashMap accessPermissions =
criteria.getCachedAccessPermissions();
// if the access permissions have not been calculated yet, get the
permissions and cache them for other
// validators to use
if (accessPermissions == null){
accessPermissions = AccessControlManager.getPermissions(...);
criteria.setCachedAccessPermissions(accessPermissions);
}
アクセス許可に関する追加の注意事項:
• wt.access.AccessControlManager には、シングルおよびマルチオブジェクトバリエーションで使用可能な以下の API があります。
◦ hasAccess - プリンシパルに指定したアクセス許可がある場合は true を、ない場合は false を返します。
◦ checkAccess - プリンシパルに指定したアクセス許可がない場合は、NotAuthorizedException をスローし、監査目的のイベントを発生させます。
◦ getPermissions - プリンシパルに付与されたアクセス許可セット (AccessPermissionSet) を返します。
• hasAccess または getPermissions を使用して、ユーザーの権限を評価し、続行します (たとえば、UI 操作検証コードがユーザーの権限に基づいて操作を無効にするなど)。
• ユーザーのアクセスを確認する 1 つの方法に、いずれかの hasAccess API を使用する方法があります。また、別の方法として、オブジェクトのアクセス許可の確認が必要なユーザーが 2 つの getPermissions API のうちの 1 つを呼び出すようにして、その結果を UIValidationCriteria に保存し、同じオブジェクトのアクセス許可の確認が必要なほかのバリデータが使用できるようにします (オブジェクトと現在のプリンシパルのドメイン、タイプ、状態が等しい場合)。この方法では、それぞれのアクセス許可チェックについて hasAccess を呼び出し、アクセス権限を評価する必要はありません。結果が保存されていなかったとしても、getPermissions API は、複数のアクセス許可をチェックする必要のあるバリデータの役に立ちます。AccessPermissionSet はコレクションで、指定したアクセス許可がセットに含まれるかどうかをチェックするメソッドを持ちます。
boolean includes(AccessPermission permission)
// Returns true if permissions in this set include rights for
the specified permission.
• checkAccess API は、例外をエンドユーザーに伝える目的以外では、ユーザーが指定したアクセス許可を持つかどうかの確認に使用すべきではありません。NotAuthorizedException が取得され、アクセス権限不足によるユーザー操作の失敗という結果にならなかった場合は、例外の監査を無効にする必要があります。詳細については、Javadoc を参照してください。
経験に基づいた方法: 操作/属性/コンポーネントごとに 1 つのバリデータ
1 つのバリデータが複数の関連のない操作に登録されることがないように注意してください。これを行うと、if/else ブランチが大量にでき、非常に大きなメソッドになりがちです。そのようなメソッドはメンテナンスが難しく、回帰しやすくなります。
通常、複数の操作/コンポーネントに単一のバリデータを使用するのは、それらのコンポーネントが完全に同一の検証ロジックを共有するか、either/or シナリオがある場合に限られます。either/or シナリオとは、特定の操作メニューで、actionA または actionB のどちらか一方のみ (両方は不可) を表示しなければならない場合のことです。これ以外のケースでは、操作/コンポーネントごとに 1 つのバリデータを登録するのがベストプラクティスです。
WTReferences をインフレートしないこと
以下のようなバリデーションコードを書きたくなるかもしれませんが、これは行わないでください。
@Override
public UIValidationResultSet performFullPreValidation
(UIValidationKey validationKey,
UIValidationCriteria validationCriteria, Locale locale)
throws WTException
{
Persistable contextObject =
validationCriteria.getContextObject().getObject();
WTContainer container =
validationCriteria.getParentContainer().getReferencedContainer();
if (!contextObject instanceof WTPart){
...
}
if (!container instanceof PDMLinkProduct){
...
}
}
前述のコードは UIValidationCriteria にある WTReferences を Persistables にインフレートするという比較的コストの高い操作を実行しています。このようなオブジェクトのインフレートが避けられないケースもないとは言えませんが、ほとんどは避けられます。コンテキストオブジェクトまたは親コンテナが、あるクラスのインスタンスかどうかを確認したいだけの場合は、次のように isAssignableFrom() メソッドを使用します。
@Override
public UIValidationResultSet performFullPreValidation
(UIValidationKey validationKey,
UIValidationCriteria validationCriteria, Locale locale)
throws WTException
{
WTReference contextObjectRef =
validationCriteria.getContextObject();
WTContainerRef containerRef =
validationCriteria.getParentContainer();
if
(!WTPart.class.isAssignableFrom(contextObjectRef.getReferencedClas
s())){
...
}
if (!PDMLinkProduct.class.isAssignableFrom(containerRef.getReferenced
Class())){
...
}
}
Null 値の処理
ある製品の特定のページの特定の操作について、バリデータまたはフィルタを記述し、ビジネスロジックを実行するために、UIValidationCriteria のいずれかの属性を必要とする場合があります。たとえば、情報ページの第 3 レベルのテーブルで作業しているとします。ジェネリック部品の情報ページについては、そのテーブルのツールバーに操作を表示したくない場合があります。そのような場合は、以下のようにします (このコードは例として参照し、写さないでください):
if
(((WTPart)validationCriteria.getContextObject().getObject()).getGe
nericType()
.equals(GenericType.GENERIC)){
...
これは、部品詳細ページで操作を試しただけのテストケースであれば問題なく動作します。しかし、その操作がホームページ、または製品リストページのいずれかのテーブルのツールバーに表示されたらどうでしょうか? そのようなページからは、上記のコードは NullPointerException をスローします。validationCriteria.getContextObject() が null を返すからです (正しい動作です)。
これを回避するにはいくつか方法があります。まず、UIValidationCriteria から取得した値をチェックし、null でないことを確認する方法があります。値が null の場合は、警告を記録し、super.[実装している任意のメソッド](key, criteria, locale); を呼び出します。
別の方法としては、比較を行うときに、"予想される" 値で .equals オペレーションを使用します。以下に例を示します。
if
(ComponentType.WIZARD.equals(validationCriteria.getComponentType()
)
NOT
if
(validationCriteria.getComponentType().equals(ComponentType.WIZARD
))
通常、作成した使用シナリオで null 値が検証の続行を許可しないというだけでは、すべての使用シナリオですべての動作を停止させることにはなりません。
@Override アノテーションの使用
ootb 提供クラスのメソッドをオーバーライドするときは、常に Override アノテーションを使用するようにしてください。
UIValidationCriteria.toString()
UIValidationCriteria の toString() はオーバーライドされず、コンテンツ情報を与えます。以下のように、ログ作成メソッドに使用できます。
public String toString_heavy(Logger logger, Level level)
Logger の Level が指定された Level と一致する場合は、情報を返します。このメソッドは比較的負担の大きい計算を実行するので、使用する際は注意が必要です。