I am!
do they, who the hell are they anyway?, really expect you to add on 50 to 100 fields with all those clumsy interface buttons the normal validators?
examples? let’s count the steps it takes me to add a validator:
1. select the field in the XPage
2. open properties view
3. “enlarge” (or drag it upwards) the properties view (cause it’s always to slim in height)
4. click “All properties”
5. scroll down to data or click these on the first to sections:
6. click on the “validators” which makes some equally small buttons visible
7. click the plus button to add a validator:
8. select the validator you want to apply
9.-x. add the required property values
Now repeat that for about 50 or more fields on an XPage!!! I don’t think your customer is happy to pay your for this stupid/error prone clumsy work.
well I don’t know about you.. but I want to keep as much code centralized as I can. I am such a lazy person. So I tried to follow up on our method we had in our plain old Notes framework: field validation configured via setup documents!
So I had to figure out how custom validators work. This journey also took some hours, but within a day I got all working. And this included getting the JSF phases to understand (see my other post about that topic)
Here the result:
The display will be handled by the errorMessage/errorMessages control: I tend to think of the one which is connected to the field as the “summary” message (reason is it should no distract the look and feel of your input form too much), and the ones collecting all messages as the “detail” messages, but I think its actually the other way around
Code your validator:
public class CustomValidator implements Validator {
public void validate(FacesContext facesContext, UIComponent field,
Object arg) throws ValidatorException {
String value = arg.toString();
// add here your validation conditions for which a message should be
// displayed and then
// create a FacesMessage which then will show up next to your field in
// the
String m1 = “ups something went wrong: summary”;
String m2 = “ups something went wrong: detail”;
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, m1, m2);
throw new ValidatorException(msg);
}
}
DO NOT HANDLE THE EXCEPTION!!!
first I had a try/catch block installed.. but what happened? the messages showed up and yet the document could be save anyway!!! what a disaster… so get rid of the try/catch and let the ValidatorException be thrown and handled by the servlet engine.
faces-config.xml:
<validator>
<validator-id>idOfYourOwnValidator</validator-id>
<validator-class>com.abb.xpages.framework.CustomValidator</validator-class>
</validator>
we are done! wait!!! and how do you get this validator applied? wasn’t that the whole point? not having to repeat all those 10 steps over and over again?
well… please read this post about the phase-listener:
http://in-mood.blogspot.ch/2012/09/jsf-phases-in-xpages.html
there you add a condition which will in the beforeValidations phase add all the required validators:
add this to your phase-listener:
if (event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)) { CustomValidator v = new CustomValidator(); v.addValidators(); }
add this to your CustomValidator:
public void addValidators(){
// repeat this step (maybe in a proper loop for all fields which require the validator
// Util is a class I created with an abstract method “findComponent”, abstract such that I don’t
// have to always instantiate it whereever I use it
field = (UIInput) Util.findComponent(FacesContext
.getCurrentInstance().getViewRoot(),
“fieldNameOnTheXPage”);
// add your validator
Validator[] validators = field.getValidators();
// make sure you only add the validator once, otherwise the
// messages control will display one
// message for every roundtrip the page has done to the server!
if (0 == validators.length) {
field.addValidator(facesContext.getApplication()
.createValidator(“idOfYourOwnValidator“));
}
for single instances you can of course add it manually as well (such as for testing if it actually works:)
now there is one minor drawback in this whole process:
on my local machine the “createValidator” won’t work due to security issues.
on our test server it works, I assume it has to do with a grant * something statement I once added to the java.policy in the jvmlibsecurity directory of the program directory
update:
Add this to the grant section:
permission java.lang.RuntimePermission “getClassLoader”;
I am actually now “finetuning” the “addValidators” as I could not yet figure out how to create the “required” Validator myself such that it adds the message to the control instead of alerting it in the client!