Home » Eclipse Projects » Eclipse Scout » Validation rules(User defined validation at server side only)
|
Re: Validation rules [message #776584 is a reply to message #776521] |
Sun, 08 January 2012 21:07 |
Jeremie Bresson Messages: 124 Registered: November 2010 |
Senior Member |
|
|
I am not sure there is something like that yet...
In the store(FormData) and create(FormData) functions of your process service. If you have a blocking task you throw a ProcessingException (technical error) or a VetoException (business logic error/validation) and it will be handled and returned to the server. The transaction is rolled back.
The idea is not to continue to see all what is not valid (business logic) and return a list to the client. I would say that for those tests, you are too late. At this point validating "again" the inputs is for other developers (preventing them to misuse your service, or giving them a better explanation than "SQL-Error Constraint violated") and a security matter (preventing bad-clients to misuse the service).
How I would do it:
In the form handler, you have 2 additional functions:
- execCheckField()
- execValidate()
that you can override and where you can add some logic (including a call of a new function checkStore() or checkCreate() in your process Service) in order to check some additional conditions requiring a DB query.
If not successful, you return false in order to stop the task and to ask the user to correct some data.
You can set an error/warning/info status on your field. You can also display a message box.
These cases are very Application specific... but if you need the same kind of logic in different forms, you can pack them in some Utility / Helper class or even a specific Abstract FormHandler that you reuse between multiple forms.
.
[Updated on: Mon, 09 January 2012 11:13] Report message to a moderator
|
|
|
Re: Validation rules [message #777337 is a reply to message #776584] |
Tue, 10 January 2012 10:00 |
Bertin Kiekebosch Messages: 330 Registered: August 2011 |
Senior Member |
|
|
Hi,
checking at the client side is very usefull for the end user and means direct feedback.
On the server however, I want to be absolutely sure, that whatever I store in the database is correct. So right before the data is stored in the database I do some checks. If a mandatory value is empty, often this means that I, as a developer, have made a mistake in my client application.
But what if I expose the same service in another way like a webservice. Who checks the input then. The only point to be absolutely sure that the data is valid is checking it just before you save it into the database.
So what I do now in the ProcessService is:
@Override
public AccountFormData store(AccountFormData formData) throws ProcessingException {
if (!ACCESS.check(new UpdateAccountPermission())) {
throw new VetoException(Texts.get("AuthorizationFailed"));
}
Validation.validateBeforeUpdate(new AccountValidator(), formData);
SQL.update(
"UPDATE account SET" +
" name = :naam," +
" valid_through = :geldigTot," +
" fk_medewerker = :medewerker," +
" fk_client = :client, " +
" active = :aktief" +
" WHERE id = :accountNr", formData);
return formData;
}
The AccountValidator makes sure that everything is correct. It can check the database, collect multiple errors and at the end it throws an VetoException. It works OK but the only drawback is that there is no real integration with the Scout validation. So the user will get messages from the scout validation or from my own validation even if they are both run server-side.
I was curious if there is some integration possible and if there is a way to add my server-side business rules and or validations to the scout framework.
regards Bertin
|
|
| | |
Re: Validation rules [message #779630 is a reply to message #777993] |
Mon, 16 January 2012 08:18 |
Ivan Motsch Messages: 154 Registered: March 2010 |
Senior Member |
|
|
Hi Bertin,
What you write is absolutely right in the following semantics:
Client form validation is a user convenience to not unnecessarily query the back-end.
Central input validation takes place in the server using a IValidator.
It is based on annotations done on service interface method parameters such as
@Mandatory, @MinValue, @MaxValue,...
For FormData objects there is an additional layer of input validation that is based on security methods
directly placed in the form data itself.
This means, a form data that is used in a webservice is checked in the scout server the same way as it is checked when it is used in a form. Provided that is contains the correpsonding rule maps inside the formdata class.
For your code and in particular when using webservices I would suggest that you add a custom annotation to the parameter in the service,
where you perform your custom checks.
@Override
public AccountFormData store(@ValidateAccountUpdate AccountFormData formData) throws ProcessingException {
SQL.update(
...
return formData;
}
The annotation ValidateAccountUpdate can be written similar to org.eclipse.scout.rt.shared.validate.annotations.Mandatory.
All following is just customizing of default input validation handling for your project(s), for simplicity i will prefix it with "Bki".
Override ServiceTunnelServlet
public class BkiTransactionDelegate extends ServiceTunnelServlet {
...
@Override
protected ServiceTunnelResponse runServerJobTransactionWithDelegate(ServiceTunnelRequest req, Bundle[] loaderBundles, Version requestMinVersion, boolean debug) throws Exception {
return new BkiTransactionDelegate(loaderBundles, requestMinVersion, debug).invoke(req);
}
}
Override DefaultTransactionDelegate this is where your BkiValidator is effectively integrated.
public class BkiTransactionDelegate extends DefaultTransactionDelegate {
public BkiTransactionDelegate(Bundle[] loaderBundles, Version requestMinVersion, boolean debug) {
super(loaderBundles, requestMinVersion, debug);
}
@Override
protected void validateInput(IValidationStrategy validationStrategy, Object service, Method op, Object[] args) throws Exception {
new BkiValidator(validationStrategy).validateMethodCall(op, args);
}
}
Subclass DefaultValidator to integrate the custom annotation 'ValidateAccountUpdate'
public class BkiValidator extends DefaultValidator {
public BsiCrmValidator(IValidationStrategy validationStrategy) {
super(validationStrategy);
}
@Override
protected void addCheckFromAnnotation(ValidateCheckSet localSet, ValidateCheckSet subtreeSet, Annotation a, Object value) throws Exception {
if (a.annotationType() == ValidateAccountUpdate.class) {
ValidateAccountUpdate x = (ValidateAccountUpdate) a;
(x.subtree() ? subtreeSet : localSet).addCheck(new ValidateAccountUpdateCheck());
return;
}
super.addCheckFromAnnotation(localSet, subtreeSet, a, value);
}
Finally ValidateAccountUpdateCheck is the implementation of your server-side check.
public class ValidateAccountUpdateCheck implements IValidateCheck {
public static final String ID = "validateAccountUpdate";
public ValidateAccountUpdateCheck() {
}
@Override
public String getCheckId() {
return ID;
}
@Override
public boolean accept(Object obj) {
return obj instanceof AccountFormData;
}
@Override
public void check(Object obj) throws Exception {
AccountFormData formData=(AccountFormData)obj;
//XXX check the form data
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}
|
|
|
Goto Forum:
Current Time: Fri Apr 26 13:45:45 GMT 2024
Powered by FUDForum. Page generated in 0.03051 seconds
|