Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » scout » Validation rules(User defined validation at server side only)
Validation rules [message #776521] Sun, 08 January 2012 17:08 Go to next message
Bertin Kiekebosch is currently offline Bertin KiekeboschFriend
Messages: 309
Registered: August 2011
Senior Member
If you are setting mandatory to true or define a max length on a field, at runtime validation rules are created and executed. Default they are only executed at the client but you can make them execute at the server (See http://wiki.eclipse.org/Scout/Concepts/Communication).

I need additional rules that are only executed at the server, because I have to check the database.

What I already did is create a check at the server side and throw a VetoException. This works fine but is not a very nice integration into the Scout framework. A problem with this is that or the "standard" Scout exceptions are thrown or my VetoException is thrown but they are not collected and presented in one list of errors.

So the question is, can I create my own validation rules that are only excuted at the server side and that are well integrated in the Scout framework.

regards Bertin
Re: Validation rules [message #776584 is a reply to message #776521] Sun, 08 January 2012 21:07 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 118
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 Go to previous messageGo to next message
Bertin Kiekebosch is currently offline Bertin KiekeboschFriend
Messages: 309
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 #777359 is a reply to message #777337] Tue, 10 January 2012 10:32 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 797
Registered: October 2011
Senior Member
To my mind, it is correct to do a Validation before you write in the DB (for the mentionned reasons: Webservice, Bad Client, Developer mistake...).


When you speak from a list of error. What is the form? Something like a HashMap <Field, Message>?

When you speak from a Scout Integration ? what do you expect on the client ? Having error Status in the Client on the fields that do not validate. Something else ?


From my understanding, the Scout Validation Framework is a replication server-side of the checks that are defined in the client on the fields. I need to have a better look at it.

.
Re: Validation rules [message #777993 is a reply to message #777359] Wed, 11 January 2012 09:08 Go to previous messageGo to next message
Bertin Kiekebosch is currently offline Bertin KiekeboschFriend
Messages: 309
Registered: August 2011
Senior Member
At the server we execute several checks. These checks are not directly related to a field, for example, some users are not allowed to validate orders that exeed a specified value. We have many of these kind of checks. To execute such kind of checks we often have to read different tables.

What I do now is that if a check fails, I just add a error message (String), to a list of strings.

validationContext.addError("Account kan niet aktief zijn met een verlopen Geldig tot datum");


At the end of the validation I concatenate all the messages with a newline in between and create a VetoException.

So the errors are just a list of Strings.

What I mean with the integration is that if I do the scout form validation at the server side, and my own validations, that if there are errors in both areas, only one Veto exceptions is thrown that contains all messages.

So in fact I need some point where the Scout Validation frameWork calls my own (Server side only) validations and that it is possible to add additional error messages.

Maybe it is there and is all this possible but I have not found it yet.









Re: Validation rules [message #779630 is a reply to message #777993] Mon, 16 January 2012 08:18 Go to previous message
Ivan Motsch is currently offline Ivan MotschFriend
Messages: 100
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();
  }

}

Previous Topic:hibernate / jpa documentation
Next Topic:Process hangs
Goto Forum:
  


Current Time: Sat Nov 29 02:57:16 GMT 2014

Powered by FUDForum. Page generated in 0.01912 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software