Grundlegende Anpassung > User Interface Customization > Presenting Information in the UI > UI Validation > Procedure – Pre-Validation > Implementing Validators for Pre-Validation
  
Implementing Validators for Pre-Validation
Assuming the solution-based, role-based, and filter checks pass, the final thing the validation service will do when performing a pre-validation activity is to call the validator associated with a UI component. As previously mentioned, a typical validator will contain pre-validation logic that is unique to a single UI component or a small set of related components. In other words, it is possible to associate a single validator with multiple UI components, if the validation logic is identical for those components. But in that case, you may also want to consider a filter. The advantage of using a filter is that you would always have the option to add a validator at a later time if the logic for one of the components deviates from the others.
Limited Pre-Validation vs. Full Pre-Validation
There are actually two pre-validation methods defined in a validator – one method is for “limited” pre-validation, and the other is for “full” pre-validation. The respective methods you’ll implement are called performLimitedPreValidation() and performFullPreValidation().
The distinction between limited pre-validation and full pre-validation is made for performance considerations. The client infrastructure will ask the validation service to perform limited pre-validation in situations where performance is essential. Currently, the only scenario when limited pre-validation is requested for actions is when the row-level “action icons” are being pre-validated in a table or tree. For attributes, limited pre-validation is always requested.
As a validator developer, you don’t need to figure out when limited pre-validation is called vs. when full pre-validation is called. You just implement both methods (performLimitedPreValidation() and performFullPreValidation()) in your validator and assume that the infrastructure will call the appropriate method under the given conditions. It’s possible and, in many cases, likely that your performLimitedPreValidation() and performFullPreValidation() methods will have the exact same logic.
Limited Pre-Validation Explained
Consider a table that has 50 rows, with five row-level action icons in each row. Before the table is rendered, there will be 250 (50 rows x 5 actions) pre-validation checks performed to determine which actions should be available in each row. If each of those validation checks even takes .01 second, that means that 2.5 seconds will be spent on pre-validation alone before the page is even rendered.
In this case, we are willing to sacrifice validation “accuracy” for “performance”. The client infrastructure will request “limited” pre-validation from the validation service in this case. The expectation is that your validator will not perform any “expensive” validation checks when limited pre-validation is invoked, erring on the side of enabling the action.
In other words, suppose that you need to check some access permissions in order to really determine whether or not an action should be available to a user, but you know that access permissions are expensive to check. In your validator’s performLimitedPreValidation() you would skip the access permission check and assume that the user has the appropriate permissions. The worst case scenario is that the action is displayed and enabled for the user, but once they try to invoke it, post-select validation performs a more complete check and denies the user from performing the action. This is what is meant by sacrificing “accuracy” for “performance” in limited pre-validation.
Full Pre-Validation Explained
On the other hand, suppose you’re pre-validating an action in a “drop-down” list of actions in a table row, or on an info page. Since we’re using Ajax to populate these dropdown lists once the user selects them (as opposed to when the page is initially rendered), performance is not as critical. At most, we’ll be validating several actions, but only for a single context object.
In this case, it is acceptable to have slower performance in favor of validation accuracy. Considering the same example we described for limited pre-validation, if you need to perform some access permission checking to determine whether or not an action should be available to a user, you can afford to make that check in your validator’s performFullPreValidation() method. It may take longer to perform the check, but since the number of validations being performed before the page (or Ajax component) is rendered is manageable, the less-performant check is acceptable.
Keep in mind that in many situations, your validator’s performFullPreValidation() and performLimitedPreValidation() method implementations will be identical.
Creating a Validator
Creating a validator class should be fairly simple. All you need to do is create a class that extends com.ptc.core.ui.validation.DefaultUIComponentValidator.
The class below represents a skeleton for a simple validator class.
package com.ptc.windchill.enterprise.myPackage.validators;

import com.ptc.core.ui.validation.DefaultUIComponentValidator;

public class MyValidator extends DefaultUIComponentValidator{
//override one or more validation methods from
DefaultUIComponentValidator
}
Implementing Pre-Validation Methods
Once you’ve created a validator class skeleton, if you’re adding pre-validation logic for an attribute, you’ll want to implement the performLimitedPreValidation() method. If you’re adding pre-validation logic for an action, you’ll want to implement both the performFullPreValidation() and performLimitedPreValidation() methods. As mentioned in the previous sections regarding limited pre-validation and full pre-validation, the implementations of these two methods may be identical, or they may differ. The class on the next page contains some skeleton implementations of these methods.
public class MyValidator extends DefaultUIComponentValidator{
@Override
public UIValidationResultSet performFullPreValidation()
(UIValidationKey validationKey,
UIValidationCriteria validationCriteria, Locale
locale) throws WTException {
UIValidationResultSet resultSet =
UIValidationResult.newInstance();

// perform your business logic here
// if you want to enable the action/component, do this:
//
resultSet.addResult(UIValidationResult.newInstance(validationKey,
// UIValidationStatus.ENABLED));
// if you want to disable the action/component, do this:
//
resultSet.addResult(UIValidationResult.newInstance(validationKey,
// UIValidationStatus.DISABLED));
// if you want to hide the action/component, do this:
//
resultSet.addResult(UIValidationResult.newInstance(validationKey,
UIValidationStatus.HIDDEN));

return resultSet;
}

@Override
public UIValidationResultSet performLimitedPreValidation()
(UIValidationKey validationKey,
UIValidationCriteria validationCriteria, Locale
locale) throws WTException {
UIValidationResultSet resultSet =
UIValidationResultSet.newInstance();

// perform your business logic here
// if you want to enable the action/component, do this:
//
resultSet.addResult(UIValidationResult.newInstance(validationKey,
// UIValidationStatus.ENABLED));
// if you want to disable the action/component, do this:
//
resultSet.addResult(UIValidationResult.newInstance(validationKey,
// UIValidationStatus.DISABLED));
// if you want to hide the action/component, do this:
//
resultSet.addResult(UIValidationResult.newInstance(validationKey,
UIValidationStatus.HIDDEN));

return resultSet;
}
}
Registering Validators
Once you’ve created your validator and implemented the appropriate pre-validation method(s), the only thing left to do is to register it. You need to register your validator to associate it with the action or attribute it is intended to validate.
When registering a validator for an action, you may make the association using the action name only, or using a combination of action name and object type. In most cases, using just the action name to identify your validator is sufficient and preferred. When registering a validator for an attribute, you make the association using the attribute’s descriptor ID.
Basic Validator Registration
To register your validator (using only the action name for an action), you need to add an entry to *service.properties.xconf like this:
<Service context="default"
name="com.ptc.core.ui.validation.UIComponentValidator">
<Option requestor="null" serviceClass="[your fully-qualified
Validator class
]"
selector="[action name/attribute descriptor ID]" />
</Service>
Once propagated to *service.properties, it should produce an entry like this:
wt.services/svc/default/com.ptc.core.ui.vali
dation.UIComponentValidator/[action name/attribute descriptor ID]/null/0=[your fully-
qualified Validator class
]/duplicate
Note that in this case, the requestor attribute is null, meaning the action’s object type is not used in the lookup.
Type-Based Validator Registration
If you feel you have a case where it makes sense to register your validator using an action’s object-type in addition to action name, it is very similar to registering a validator using only the action name. The difference lies in the requestor attribute in the properties entry. For validators that do not use an object type, the requestor attribute is set to null. For a validator to be registered using object type, the requestor value will be the fully-qualified class name of the type it is to be registered for.
The class name that is used in the requestor attribute corresponds to a class name from actions.xml.
For example, consider this fragment of an actions.xml file (NOTE: some text eliminated for readability):
<objecttype name="problemReport" class="wt.change2.WTChangeIssue"
...>
<action name="create" >
...
</action>
...
</objecttype>
In this case, the action we're looking at is called create. Obviously, it's likely that there will be multiple actions defined in the system named create. However, the validation rules for each create action may be different, depending on the type of object being created. Therefore, it might make sense to have separate validators for the create action for, say, a Problem Report and the create action for a Part.
Suppose we have a validator defined called com.ptc.windchill.enterprise.change2.validators.ChangeMgmtCreateWizardsValidator that we want to register for create actions, but only if the action is to create a Problem Report.
We could look at the actions.xml entry above and see that the create action for a Problem Report is actually defined for an objecttype whose name is problemReport and, more importantly, whose class is wt.change2.WTChangeIssue.
By using that class value from actions.xml as the requestor attribute in our properties entry, we can tell the validation service that we only want to register our validator (com.ptc.windchill.enterprise.change2.validators.ChangeMgmtCreateWizardsValidator) for create actions whose object type is wt.change2.WTChangeIssue, like this:
<Service context="default"
name="com.ptc.core.ui.validation.UIComponentValidator">
<Option

serviceClass="com.ptc.windchill.enterprise.change2.validators.Chan
geMgmtCreateWizardsValidator"
selector="create" requestor="wt.change2.WTChangeIssue" />
</Service>
That's really all there is to it. Basically, if you want to register your validator for an action, but only if that action is associated with a certain object type (in actions.xml), you use the class attribute from actions.xml as the requestor attribute in your properties entry.
A few notes:
This type-based lookup is currently only available for actions defined in actions.xml. It will not work for attributes or other UI components.
For this to work, the class attribute from your actions.xml entry needs to be a concrete class (not an interface - there are many cases where the class attribute is currently set to wt.fc.Persistable). Changing an existing class attribute from an interface to a concrete class is OK in most cases. But you should check with the owner of the actions.xml file you're modifying before doing so.
Verifying Validator Registration
There is a command line report you can run to see which validators are registered for a given action or attribute. If your validator is not appearing in this report, that means it is not registered correctly, and will never get called.
Examples follow:
Finding a single validator (non-type based)
Usage example 1 - find the validator registered for the pasteAsCopy action:
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory
pasteAsCopy
Registered validators:
pasteAsCopy ->
com.ptc.core.foundation.saveas.validators.PasteValidator
Finding multiple validators (non-type based)
Usage example 2 - find the validators registered for the setState and pasteAsCopy actions:
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory
setState pasteAsCopy
Registered validators:
setState ->
com.ptc.windchill.enterprise.lifecycle.validators.SetStateValid
ator

pasteAsCopy ->
com.ptc.core.foundation.saveas.validators.PasteValidator
Finding a single validator (type-based)
Usage example 3 - find the validator registered for the create action whose objecttype name attribute in actions.xml is problemReport. (Note: method server must be running for type-based lookup)
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory
create:problemReport
Registered validators:
create:problemReport(wt.change2.WTChangeIssue) ->
com.ptc.windchill.enterprise.change2.validators.ChangeMgmtCreat
eWizardsValidator
Finding multiple validators (mix of type-based and non-type based)
Usage example 4 - find the validator registered for the pasteAsCopy action and the create action whose objecttype name attribute in actions.xml is problemReport. (Note: method server must be running for type-based lookup)
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory
pasteAsCopy create:problemReport
Registered validators:
pasteAsCopy ->
com.ptc.core.foundation.saveas.validators.PasteValidator
create:problemReport(wt.change2.WTChangeIssue) ->
com.ptc.windchill.enterprise.change2.validators.ChangeMgmtCreat
eWizardsValidator
Procedure – Pre-Validation