Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Strange behavior of server side validation

    I am experimenting with server side validation of ListGrid data and the behavior I observe is:

    1/ Whenever a field is changed and the change is submitted to the grid, the grid sends unconditionally to the server 2 requests: one for validation and then one for update.
    2/ On the server my custom validator is called by SQLDataSource 2 times - once during execution of the validation request and once during execution of the update request.
    3/ On the first call to the validator it gets (in the "record" parameter) data which is a merge of the changed values and the old valies in the request.
    4/ On the second call to the validator it gets only the primary key and the new values.
    5/ Whenever a new record is submitted to the grid it issues as many validation requests to the server as is the number of fields with attached server side validators followed by a create request.

    The problems I have with all this are:

    1/ Why the grid issues upon data change a validation request if it is unconditionally followed by an update request which triggers validation too?
    2/ Why are the validation requests upon record creation so many and why are they issued at all if the unconditionally following create operation triggers validation too?
    2/ Why is it that during an update operation the (SQL) data source does not merge changed and old values prior to calling the validator(s)?
    3/ Is there a way to get hold of the old values from the request in my custom validator? I looked at all required and optional arguments and found so far no way that would make sense.

    The reason why old data matters much to me is that I want to be able to do validation based on relations between feelds (e.g. - comparison) rather than individual values only. At present I am forced to pull old data from the database which is doable but much more expensive than getting the old data from the request.

    Can somebody please answer the questions above?

    #2
    Stop at #1 - that's not normal and suggests bad settings. You may have set saveByCell:true (causing updates on every cell change) while also setting validateByCell:true?

    If you only want to save on row change (the default) set both to false.

    Comment


      #3
      I probably did not explain this clearly enough. Submission to the server does not happen upon individual cell changes but when I finish editing a row.

      Comment


        #4
        P.S.: I added just in case setSaveByCell(false) and setValidateByCell(false) and nothing changed. Here is all my grid initialization code :
        Code:
                final ListGrid detailGrid = new ListGrid();
                detailGrid.setWidth100();
                detailGrid.setHeight(224);
                detailGrid.setCellHeight(22);
                detailGrid.setShowRowNumbers(true);
                detailGrid.setCanEdit(detailPermissions.isUpdateAllowed());
                detailGrid.setLayoutAlign(Alignment.CENTER);
                detailGrid.setAutoSaveEdits(true);
                detailGrid.setConfirmDiscardEdits(true);
                detailGrid.setConfirmCancelEditing(true);
                detailGrid.setSaveByCell(false);
                detailGrid.setValidateByCell(false);
                detailGrid.setDataSource(detailSource);

        Comment


          #5
          P.S.S.: I worked out a way to avoid pulling unchanged fields from the database. I do that by forcing within a custom data source full update like this:
          Code:
                  Map newValues = req.getValues();
                  Map oldValues = req.getOldValues();
                  Set oldKeys = oldValues.keySet();
                  for (Object key : oldKeys) {
                      if (newValues.get(key) == null) {
                          newValues.put(key, oldValues.get(key));
                      }
                  }
          This solves my most annoying problem but the solution is still suboptimal. And there is still redundancy in the requests (validation request(s) followed unconditionally by create/update which trigger validation again).

          Comment


            #6
            It's not normal, even with those settings, to see a request for validation followed by a separate request for save. The code you've posted, if added to a sample, will not reproduce the problem. Let us know if you can modify a sample to reproduce the problem.

            Comment


              #7
              Thank you. It is good to know that redundant validation requests are not an expected behavior. What I noticed for now is that they only happen with grids which are brought up as an expansion component of another grid. Will be digging further...

              Any hints on the issue of access to values of unchanged fields in validators upon update? As I wrote, I in a way solve it but now I have problems with built-in "isRequired" validators. Apparently they do not buy updates of correspondent fields even if the value is not really changed.

              Comment


                #8
                P.S. : Very sorry about the typo. I meant "usUnique" validators.

                Comment


                  #9
                  Having trouble following what you mean about unchanged values and required validators - can you rephrase?

                  Comment


                    #10
                    Sure. Upon update operation server side validator gets a "Map record" argument which contains the primary key and the changed values but does not contain the values which were not changed and need not be updated. The problem with this is that I may need to compare a changed value with a value which was not change in order to validate the changed value.

                    Comment


                      #11
                      I found out that apparently redundant validation requests to the server are issued by the client whenever there is a server-side validator (be it built-in or serverCustom) defined for a field and the value of that field has been changed during the editing of a grid record. This also applies to creation of new records. My previous observation re extension objects turned out to be irrelevant.

                      To reproduce this it is sufficient to put on an arbitrary field e.g. the following validator (other validator types work as well) :
                      Code:
                                  <validators>
                                      <validator type="isUnique"/>
                                  </validators>
                      Then change the value of the field in a grid record and finish editing. Or/and create a new record.

                      Comment


                        #12
                        Sorry about discussing 2 distinct issues at the same time but let me just in case and in addition to the post above summarize also the second issue under discussion so it does not get lost:

                        Server side custom vaidator method has generally the following signature:
                        Code:
                            public boolean condition(Object value, Validator validator,
                                                     String fieldName, Map record)
                            // Optional arguments:
                            //
                            // DataSource          dataSource,
                            // RequestContext      requestContext,
                            // HttpServletRequest  httpServletRequest,
                            // HttpServletResponse servletResponse,
                            // ServletContext      servletContext,
                            // HttpSession         httpSession
                            // RPCManager          rpcManager
                        The value to be validated is in the "value" argument. In order to do the validation I may need to compare it to the value of another field. The natural place to look for that second field is the "record" argument. Upon an update operation though "record" contains only fields whose value has changed. So how do I get access to the field I need if it's value has not changed?

                        This problem applies also to validation by velocity expressions because I observe exceptions in such validators under similar conditions. For example the following validator:
                        Code:
                        <field 
                        	name="END_DATE" 
                        	type="date">
                        	<validators>
                        		<validator
                        		type="serverCustom"
                        		errorMessage="End date must be after start date!"
                        		serverCondition="$value.after($record.START_DATE)"/>
                        	</validators>
                        </field>
                        throws an exception upon update operation if the value of the value of START_DATE was not changed.

                        Regards
                        Nikolay

                        Comment


                          #13
                          Any advice on this?

                          Regards
                          Nikolay

                          Comment


                            #14
                            dsRequest.oldValues is sent from the client, hence it is spoofable - it is intended for the scenario of checking whether there have been concurrent edits when the user has the ability to proceed with the save anyway.

                            For a data validity or security check, you want to get the latest values from the database, which is secure. These two samples show doing a related DSRequest in the context of server-side validation.

                            On your issue with extra requests - can you actually take that isUnique validator and add it to a sample that comes with the SDK and reproduce the issue you're talking about? Because a lot of other settings could be involved here - the clearest thing would be if this can be reproduced in a sample.

                            Comment


                              #15
                              Thank you, Isomorphic. I recognize the validity of your position even though I do not share it. I deal with concurrency by automated optimistic locking implemented in a custom data source and if I can not trust the values from the client for some other reason, I will rather not allow updates all.

                              There are of course workarounds which bypass this design and so far I think I will be using some but I will also give that a second thought based on your concerns.

                              On the issue of redundant validate requests, here is a modified worldDS,ds.xml from the EE showcase :
                              Code:
                              <DataSource
                                  ID="worldDS"
                                  serverType="sql"
                                  tableName="worldDS"
                                  testFileName="/ds/test_data/world.data.xml"
                              >
                                  <fields>
                                      <field name="pk"            type="sequence"   hidden="true"            primaryKey="true" />
                                      <field name="countryCode"   type="text"       title="Code"             required="true"   />
                                      <field name="countryName"   type="text"       title="Country"          required="true"   />
                                      <field name="capital"       type="text"       title="Capital"          >
                              		<validators>
                              			<validator type="isUnique"/>
                              		</validators>
                                      </field>
                                      <field name="government"    type="text"       title="Government"       length="500"      />
                                      <field name="continent"     type="text"       title="Continent"        >
                                          <valueMap>
                                              <value>Europe</value>
                                              <value>Asia</value>
                                              <value>North America</value>
                                              <value>Australia/Oceania</value>
                                              <value>South America</value>
                                              <value>Africa</value>
                                          </valueMap>
                                      </field>
                                      <field name="independence"  type="date"       title="Nationhood"          />
                                      <field name="area"          type="float"      title="Area (km&amp;sup2;)" />
                                      <field name="population"    type="integer"    title="Population"          />
                                      <field name="gdp"           type="float"      title="GDP ($M)"            />
                                  </fields>
                              </DataSource>
                              With this data source and no modifications to code I changed the capital of Bermuda through the "Basic Connector" example. Here are the payloads of the requests that I observed in a Tomcat log (it seems the forum does not like catalina.out format, so I can not provide the complete log) :

                              Code:
                              {
                                  values:{
                                      countryName:"Bermuda",
                                      area:50,
                                      gdp:1700,
                                      continent:"North America",
                                      countryCode:"BD",
                                      independence:new Date(1225670400000),
                                      government:"dependent territory of the UK",
                                      capital:"Whatever",
                                      population:62099,
                                      pk:0,
                                      _selection_5:true
                                  },
                                  operationConfig:{
                                      dataSource:"worldDS",
                                      operationType:"validate"
                                  },
                                  validationMode:"partial",
                                  appID:"builtinApplication",
                                  operation:"worldDS_validate",
                                  oldValues:{
                                      countryName:"Bermuda",
                                      area:50,
                                      gdp:1700,
                                      continent:"North America",
                                      countryCode:"BD",
                                      independence:new Date(1225670400000),
                                      government:"dependent territory of the UK",
                                      capital:"Whatever",
                                      population:62099,
                                      pk:0,
                                      _selection_5:true
                                  },
                                  criteria:{
                                  }
                              }
                              
                              {
                                  criteria:{
                                      pk:0
                                  },
                                  values:{
                                      pk:0,
                                      capital:"Whatever"
                                  },
                                  operationConfig:{
                                      dataSource:"worldDS",
                                      operationType:"update"
                                  },
                                  componentId:"isc_ListGrid_0",
                                  appID:"builtinApplication",
                                  operation:"worldDS_update",
                                  oldValues:{
                                      countryName:"Bermuda",
                                      area:50,
                                      gdp:1700,
                                      continent:"North America",
                                      countryCode:"BD",
                                      independence:new Date(1225670400000),
                                      government:"dependent territory of the UK",
                                      capital:"Hamilton",
                                      population:62099,
                                      pk:0
                                  }
                              }
                              Regards
                              Nikolay

                              Comment

                              Working...
                              X