基本的なカスタマイズ > ユーザーインタフェースのカスタマイズ > Windchill JSP フレームワークを使用した HTML クライアントのカスタマイズ > 操作とプロパティの検証ロジックの追加
  
操作とプロパティの検証ロジックの追加
このセクションでは、開発者が検証委任 (バリデータ) を実装して特定の操作または UI コンポーネントに対する検証を行うために必要な情報を示します。
目的
UI コンポーネント検証サービスは、Windchill UI に表示される操作とほかのコンポーネントの検証を実行するために呼び出される中央サービスを Windchill クライアントに提供することを目的として作成されます。サービスの呼び出しと結果の解釈は、リリース 9.0 で開発された多くの共通コンポーネントで管理する必要があります。アプリケーション開発者の主な責任は、検証サービスによって呼び出されて、特定の操作または UI コンポーネントを検証するバリデータクラスを開発することです。このドキュメントでは、バリデータクラスの作成プロセスおよび最良事例について説明します。
適用可能性
このドキュメントは、操作または UI コンポーネントが所定のページやコンテキストなどで妥当か判断するバリデータを記述する開発者が使用してください。このドキュメントでは、バリデータを呼び出して実行できる検証操作について、そのタイプごとの例を取り上げます。
構造
UI 検証サービスのクラスはすべて (注記されている場合を除いて)、com.ptc.core.ui.validation パッケージで定義されています。
バリデータの開発者はこの図のすべてのクラスを操作する必要はありませんが、その多くの適用が可能です。このドキュメントではさまざまなクラスについて説明しますが、まず、バリデータを記述する開発者は常にバリデータクラスを定義し、DefaultUIComponentValidtor を拡張する必要があります。
* 
また、要件が展開するときに、これらのクラスが更新される場合があることに注意してください。各クラスで定義されたメソッドと属性の最新セットを入手するには、Windchill Javadoc を参照してください。
参加者
このセクションの読者は、Java プログラミング言語の一般的な知識があり、Windchill ソリューションスイートを使い慣れている必要があります。
コラボレーション
バリデータ開発者は共通コンポーネントの開発者および検証サービスのほかの呼び出し側とコラボレーションを行う必要があります。このコラボレーションは、サービスの呼び出し側がすべてのデータを特定のバリデータが検証を行う必要のあるサービスに渡すことを確認するために必要です。バリデータ開発者は、特定の検証メソッドに必要なデータのリストを、そのメソッドの Javadoc に含めてください。また、メソッドによって説明されるように設計されている検証キー (操作名) のリストを含めることも役に立ちます。次に例を示します。
public class DefaultWIPValidator extends DefaultUIComponentValidator
{

/**
* This implementation of performLimitedPreValidation will check the checkout
* state of all the Workable objects in the ValidationCriteria's targetObjects
* WTCollection, and base its validation results on whether an object in the
* given state can have the specified action performed on it. (e.g., an object
* in the checked-in state can not have an undo checkout action performed on it)
*
* At a minimum, a caller of this method should provide the targetObjects
* WTCollection in the validationCriteria argument.
*
* The expected validationKey arguments for this method are:
* checkin
* checkout
* undocheckout
*
* <BR><BR><B>Supported API: </B>false
*
* @param validationKey The String identifying the action or component being validated.
* @param validationCriteria Object holding information required to perform validation tasks.
* @param locale The user's Locale. If a <i>null</i> value is passed in, the session locale will be used.
* @return UIValidationResultSet
**/
public UIValidationResultSet performLimitedPreValidation (String validationKey,
UIValidationCriteria validationCriteria, Locale locale)
throws WTException
{

}

}
結果
このドキュメントを参考にすることで、開発者はよりパフォーマンスの高い一貫したバリデータを作成できます。検証サービスの呼び出し側は、検証を行う操作または UI コンポーネントがどのようなものであっても一貫した方法で検証されていることを確認する必要があります。
実装
概要
検証 という用語の定義から始めます。この説明では、検証という用語はユーザーが表示または実行することができる内容を確認するために行われるアクティビティを意味します。次に例を示します。
「部品を作成」操作を表示する必要があるか。
このオブジェクトのチェックアウトを許可する必要があるか。
この作成ウィザードにユーザーが入力した内容に問題はないか。
この説明では、検証 は以下の 3 つの大きなカテゴリに分けられます。
事前検証
「UI でユーザーに何かを表示する必要があるか。表示する必要がある場合には、それは編集可能か、選択可能か」という問いに答えます。
たとえば、コンテナ B のユーザー A に対して、「部品を作成」操作を表示して有効にする必要があるかどうかです。
事前検証は、操作またはほかの UI コンポーネント (ステータスグリフ、属性、テーブルなど) に対して実行できます。
選択後検証
「UI で選択された操作の続行を許可する必要があるか」という問いに答えます。
たとえば、部品 A、B、および C のチェックアウトを許可できるかどうかです。
サブミット後検証
「ユーザーが入力したデータは有効か」という問いに答えます。
たとえば、ユーザーが「部品を作成」ウィザードの「次へ」をクリックしたとき、次のステップへの移動を許可するか、それともユーザーが現在のステップの一部のデータ (名前、番号など) を修正する必要があるかどうかです。
UI コンポーネント (操作) 検証サービスは、前述の各タイプの検証に対し、API を公開します。
高いレベルから見ると、共通コンポーネントまたはほかのクライアントが検証サービスの検証 API を呼び出し、1 つまたは複数の検証キー (create など、操作名として考えることができるもの) および UIValidationCriteria ビーンを渡します。このビーンには、検証を実行するために必要でクライアントによって認識されたデータが含まれています。検証サービスでは検証キーを使用して照会を実行し、検証アクティビティを実行するために呼び出す必要のあるバリデータクラスを識別します。次に、サービスはキーおよび UIValidationCriteria を特定されたバリデータに渡し、結果を待機します。バリデータからの結果がある場合、サービスは (結果のバンドルを作成し) クライアントに結果を返します。
このドキュメントではバリデータクラスおよびメソッドの作成に注目します。
パッケージ/モジュール化
UI コンポーネント検証サービスに関連するクラスはすべて、com.ptc.core.ui.validation にパッケージされています。そのソースは \Windchill\src\com\ptc\core\ui\validation モジュールにあります。開発者がバリデータ開発を行う場合は、このディレクトリのすべてのファイルを更新し、最新バージョンの Java クラスをコンパイルしてください。
バリデータを記述する開発者は、バリデータが検証する操作/UI コンポーネントにとって意味のあるパッケージまたはモジュール内にバリデータクラスを配置する必要があります。
バリデータクラスの作成
操作および UI コンポーネントの所有者は、それらの操作および UI コンポーネントを検証するバリデータを記述します。バリデータを作成するには、com.ptc.core.ui.validation.DefaultUIComponentValidator.java のサブクラスを作成する必要があります。現在、DefaultUIComponentValidator.java には 5 つのパブリックメソッドが定義されています。ユーザーのサブクラスはそのすべてをオーバーライドできます。
performFullPreValidation()
performLimitedPreValidation()
validateFormSubmission()
validateSelectedAction()
validateSelectedMultiSelectAction()
オーバーライドしないメソッドについては、DefaultUIComponentValidator クラスからデフォルトの動作 (常に有効/許可) が継承されます。
また、特定の検証キー (操作) にバリデータクラスを関連付けるプロパティのエントリを作成する必要があります。検証サービスではこれらのエントリを使用して、指定された検証キー (操作) に対する適切なバリデータを検索します。エントリは service.properties またはアプリケーションチームのサービスプロパティファイルに配置されます (エントリを配置する必要がある場合は、グループリーダーに確認してください)。このエントリは、次の形式である必要があります。
wt.services/rsc/default/com.ptc.core.ui.UIComponentValidator/<validationKey>/
null/0=com.ptc.my.validators.MyValidator
ここで、<検証キー> は操作またはコンポーネントの検証キーであり、右側の値はバリデータの完全修飾クラス名です。
バリデータの実装で実行する必要のない確認が 3 タイプあります。これらの確認は、バリデータの呼び出しの前に検証サービスによって実行されます。その確認は以下のとおりです。
役割ベースの確認 (RBUI システムへの入力に基づく操作の表示。バリデータ内で実行する必要のあるアクセス制御の確認と混同しないでください)。
インストールベースの確認 (指定されたシステムにソリューションのセットがインストールされた場合、操作または UI コンポーネントを使用できるようにする必要があるか)。
クライアントベースの確認 (DTI または PSB などの指定されたクライアントで、操作または UI コンポーネントを使用できるようにしなければならないか)。
サンプルコード
サンプルバリデータ - DefaultWIPValidator.java
* 
ソースコードは次の場所にあります: <Windchill>\src\com\ptc\windchill\enterprise\ wip\DefaultWIPValidator.java
/* bcwti
*
* Copyright (c) 2004 Parametric Technology Corporation (PTC). All Rights
* Reserved.
*
* This software is the confidential and proprietary information of PTC.
* You shall not disclose such confidential information and shall use it
* only in accordance with the terms of the license agreement.
*
* ecwti
*/
package com.ptc.windchill.enterprise.wip;
import com.ptc.core.ui.validation.*;
import java.lang.ClassNotFoundException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import org.apache.log4j.Logger;
import wt.access.AccessPermission;
import wt.access.AccessControlHelper;
import wt.epm.workspaces.EPMWorkspaceHelper;
import wt.fc.Persistable;
import wt.fc.ReferenceFactory;
import wt.fc.WTReference;
import wt.fc.collections.WTArrayList;
import wt.fc.collections.WTCollection;
import wt.folder.CabinetBased;
import wt.folder.CabinetMember;
import wt.folder.Foldered;
import wt.folder.FolderHelper;
import wt.inf.container.WTContained;
import wt.inf.container.WTContainerHelper;
import wt.log4j.LogR;
import wt.org.WTUser;
import wt.sandbox.SandboxHelper;
import wt.session.SessionHelper;
import wt.util.WTException;
import wt.vc.Iterated;
import wt.vc.VersionControlHelper;
import wt.vc.wip.Workable;
import wt.vc.wip.WorkInProgressHelper;
import wt.vc.wip.WorkInProgressState;
public class DefaultWIPValidator extends DefaultUIComponentValidator
{
private Logger
logger = LogR.getLogger("wt.method.server.httpgw");
private ReferenceFactory refFactory = null;

private static final String FULL = "full";
private static final String LIMITED = "limited";
private static final String SELECTED = "selected";

/**
* This implementation of performLimitedPreValidation will
* check the checkout state of all the Workable objects
* in the ValidationCriteria's targetObjects
* WTCollection, and base its validation results on whether
* an object in the given state can have the specified
* action performed on it. (e.g., an object
* in the checked-in state can not have an undo checkout
* action performed on it)
*
* At a minimum, a caller of this method should provide the
* targetObjects
* WTCollection in the validationCriteria argument.
*
* The expected validationKey arguments for this method are:
* checkin
* checkout
* undocheckout
*
* <BR><BR><B>Supported API: </B>false
*
* @param validationKey The String identifying the action
* or component being validated.
* @param validationCriteria Object holding information required
* to perform validation tasks.
* @param locale The user's Locale. If a null value is passed in,
* the session locale will be used.
* @return UIValidationResultSet
**/
public UIValidationResultSet performLimitedPreValidation (String valida
tionKey,
UIValidationCriteria validationCriteria, Locale loc
ale)
throws WTException
{
logger.debug("ENTERING DefaultWIPValidator.performLimitedPreValidati
on");
logger.trace(" validtionKey -> " + validationKey);
logger.trace(" validationCriteria -> " + validationCriteria.toStrin
g());

UIValidationResultSet resultSet = performWIPValidation(validationKey,
validationCriteria, locale, LIMITED);

logger.trace("RETURNING " + resultSet.toString());
logger.debug("EXITING DefaultWIPValidator.performLimitedPreValidat
ion");
return resultSet;
}


public UIValidationResultSet performFullPreValidation (String validation
Key,
UIValidationCriteria validationCriteria, Locale loca
le)
throws WTException
{
logger.debug("ENTERING DefaultWIPValidator.performFullPreValidation");
logger.trace(" validtionKey -> " + validationKey);
logger.trace(" validationCriteria -> " + validationCriteria.toString(
));

UIValidationResultSet resultSet = performWIPValidation(validationKey,
validationCriteria, locale, FULL);
logger.trace("RETURNING " + resultSet.toString());
logger.debug("EXITING DefaultWIPValidator.performFullPreValidation");
return resultSet;
}

public UIValidationResult validateSelectedAction (String validation
Key,
UIValidationCriteria validationCriteria, Locale locale)
throws WTException
{
logger.debug("ENTERING DefaultWIPValidator.validateSelectedAction");
logger.trace(" validtionKey -> " + validationKey);
logger.trace(" validationCriteria -> " + validationCriteria.toString(
));

UIValidationResult result = null;
WTReference wtRef = validationCriteria.getContextObject();
Persistable persistable = wtRef.getObject();

if (!(persistable instanceof Workable)){
return new UIValidationResult(validationKey, wtRef, UIValidat
ion
Status.DENIED, null);
}

Workable workable = (Workable)persistable;

if (validationKey.equalsIgnoreCase("checkin") || validationKey.equals
IgnoreCase("undocheckout")){
result = performCheckinValidation(validationKey, workable, SELE
CTED,
(WTUser)(validationCriteria.getUser().getPrincipal()));
}
else if (validationKey.equalsIgnoreCase("checkout")){
result = performCheckoutValidation(validationKey, workable, SELE
CTED);
}

logger.trace("RETURNING " + result.toString());
logger.debug("EXITING DefaultWIPValidator.validateSelectedAction");
return result;
}


public UIValidationResultSet validateSelectedMultiSelectAction
(String validationKey,
UIValidationCriteria validationCriteria, Locale locale)
throws WTException
{
logger.debug("ENTERING DefaultWIPValidator.
validateSelectedMultiSelectAction");
logger.trace(" validtionKey ->
" + validationKey);
logger.trace(" validationCriteria ->
" + validationCriteria.toString());

UIValidationResultSet resultSet =
performWIPValidation(validationKey,
validationCriteria, locale, SELECTED);

logger.trace("RETURNING " + resultSet.toString());
logger.debug("EXITING DefaultWIPValidator.validateSelectedMultiSelect
Action");
return resultSet;
}

// ***NOTE:
// There is no post-submit validation for the WIP actions
// (checkin, checkout, undocheckout), since there is
// no wizard launched when one of the actions
// is performed. Therefore, there is no need to define a
// validateFormSubmission method in this class.
//
// public UIValidationResult validateFormSubmission (String validationKey,
// UIValidaitonCriteria validationCriteria, Locale locale)


private UIValidationResultSet performWIPValidation(String validationKey,
UIValidationCriteria validationCriteria, Locale locale, String
validationType)
throws WTException
{
UIValidationResultSet resultSet = new UIValidationResultSet();
WTCollection targetObjects = new WTArrayList(validationCriteria.get
TargetObjects());
Iterator workableIter = getWorkableIterator(targetObjects);
Workable workable = null;

while (workableIter.hasNext()){
workable = (Workable)workableIter.next();
if (validationKey.equalsIgnoreCase("checkin") || validationKey.equal
sIgnoreCase("undocheckout")){
resultSet.addResult(performCheckinValidation(validationKey, worka
ble, validationType,
(WTUser)(validationCriteria.getUser().getPrincipal())));
}
else if (validationKey.equalsIgnoreCase("checkout")){
resultSet.addResult(performCheckoutValidation(validationKey, worka
ble, validationType));
}
}
resultSet.appendResults(processNonWorkables(targetObjects, validationKey,
validationType));
return resultSet;
}


private UIValidationResult performCheckinValidation(String validationKey,
Workable workable,
String validationType, WTUser user)
throws WTException
{
WTReference wtRef = getWTReference(workable);

if (validationType.equals(LIMITED)){
WorkInProgressState state = workable.getCheckoutInfo().getState();
if (state.equals(WorkInProgressState.CHECKED_OUT) || state.equals(
WorkInProgressState.
CHECKED_OUT_TO_SANDBOX)){
return new UIValidationResult(validationKey, wtRef, UIValidation
Status.ENABLED, null);
}
else{
return new UIValidationResult(validationKey, wtRef, UIValidation
Status.DISABLED, null);
}
}

else if (validationType.equals(FULL) || validationType.equals(SELECTED)){
UIValidationStatus goodStatus = null;
UIValidationStatus badStatus = null;

if (validationType.equals(FULL)){
goodStatus = UIValidationStatus.ENABLED;
badStatus = UIValidationStatus.DISABLED;
}
else{
goodStatus = UIValidationStatus.PERMITTED;
badStatus = UIValidationStatus.DENIED;
}

if (workable instanceof CabinetBased){
CabinetBased orig;
if (WorkInProgressHelper.isWorkingCopy(workable)) {
orig = (CabinetBased)WorkInProgressHelper.service.originalCopyOf
(workable);
}
else {
orig = (CabinetBased)workable;
}
if (isNewInWorkspace(orig)){
return new UIValidationResult(validationKey, wtRef, badStatus,
null);
}
}
if (WorkInProgressHelper.isCheckedOut(workable, user) ||
(WorkInProgressHelper.isCheckedOut(workable) &&
WTContainerHelper.service.isAdministrator(((WTContained)workable).
getContainerReference(), user))){
return new UIValidationResult(validationKey, wtRef, goodStatus,
null);
}
else{
return new UIValidationResult(validationKey, wtRef, badStatus,
null);
}
}
return new UIValidationResult(validationKey, wtRef, UIValidationStatus.
ENABLED, null);
}



private UIValidationResult performCheckoutValidation(String validationKey,
Workable workable,
String validationType)
throws WTException
{
WTReference wtRef = getWTReference(workable);

if (validationType.equals(LIMITED)){
WorkInProgressState state = workable.getCheckoutInfo().getState();
if (state.equals(WorkInProgressState.CHECKED_OUT) || state.equals(
WorkInProgress
State.CHECKED_OUT_TO_SANDBOX)){
return new UIValidationResult(validationKey, wtRef, UIValidation
Status.DISABLED,null);
}
else{
return new UIValidationResult(validationKey, wtRef, UIValidation
Status.ENABLED, null);
}
}

else if (validationType.equals(FULL) || validationType.equals(SELECTED)){
UIValidationStatus goodStatus = null;
UIValidationStatus badStatus = null;

if (validationType.equals(FULL)){
goodStatus = UIValidationStatus.ENABLED;
badStatus = UIValidationStatus.DISABLED;
}
else{
goodStatus = UIValidationStatus.PERMITTED;
badStatus = UIValidationStatus.DENIED;
}

if (isNewInWorkspace(workable)){
return new UIValidationResult(validationKey, wtRef, badStatus,
null);
}
if ((AccessControlHelper.manager.hasAccess(workable, AccessPermis
sion.MODIFY)) &&
(!WorkInProgressHelper.isCheckedOut(workable) &&
(VersionControlHelper.isLatestIteration((Iterated)workable)) &&
(!SandboxHelper.isCheckedOutToSandbox(workable)))){
return new UIValidationResult(validationKey, wtRef, goodStatus,
null);
}
else{
return new UIValidationResult(validationKey, wtRef, badStatus,
null);
}
}
return new UIValidationResult(validationKey, wtRef, UIValidationStat
us.ENABLED, null);
}


private Iterator getWorkableIterator(WTCollection targetObjects)
{
try{
return targetObjects.persistableIterator(Class.forName("wt.vc.wip.
Workable"), true);
}
catch(Exception e){
return (new ArrayList(0)).iterator();
}
}


private WTReference getWTReference(Workable workable)
{
if (refFactory == null){
refFactory = new ReferenceFactory();
}
try{
return refFactory.getReference(workable);
}
catch(WTException wte){
return null;
}
}


private static boolean isNewInWorkspace(Object object)
throws WTException
{
if(object instanceof Foldered || object instanceof CabinetMember) {
WTArrayList objArray = new WTArrayList();
objArray.add(object);
if(FolderHelper.service.getObjsInPersonalCabinets(objArray).size()
> 0) {
if(EPMWorkspaceHelper.manager.getNewObjects(objArray).size() >
0) {
return true;
}
}
}
return false;
}


private UIValidationResultSet processNonWorkables(WTCollection
targetObjects, String validationKey, String validationType)
{
UIValidationResultSet resultSet = new UIValidationResultSet();
UIValidationStatus status = null;

if (validationType.equals(SELECTED))
status = UIValidationStatus.DENIED;
else
status = UIValidationStatus.HIDDEN;
try{
targetObjects.removeAll(Class.forName("wt.vc.wip.Workable"), true);
}
catch(ClassNotFoundException cnfe){
// do nothing
}
Iterator nonWorkableIter = targetObjects.referenceIterator();
WTReference wtRef = null;
while(nonWorkableIter.hasNext()){
wtRef = (WTReference)nonWorkableIter.next();
resultSet.addResult(new UIValidationResult(validationKey, wtRef, status,
null));
}

return resultSet;
}
}
既知の使用法
このドキュメントは、操作または UI コンポーネントのバリデータを記述する開発者が使用してください。