Announcement

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

    Optimistic locking support?

    Please excuse a newbie question but I need some help in selection of a framework for a project at hand.

    And the question is : does SmartGWT data integration framework provide out of the box support for optimistic locking and if yes then what exactly support? Ideally if databinding goes all the way from the UI to the DB and back it should be possible to automatically report concurrent modification exceptions to the user and reload data being edited.

    Regards
    Nikolay

    #2
    Yes - take a look at dsRequest.oldValues. Whenever a component submits a request to save, for example a grid doing inline editing, the original values of the record are tracked and automatically submitted to the server as part of the save, where you can check them against stored values.

    Comment


      #3
      Thank you for the prompt reply.

      If I may make a comment : I have unfortunately not found yet a framework that solves this problem end-to-end but it seems to me as a task well worth end-to-end automation. There is nothing creative in it, so I would rather task with it a framework than developers. Hibernate already has some built-in support, so a framework working on top of it should be able to pick up @Version fields and process them further.

      Regards
      Nikolay

      Comment


        #4
        You are just a few lines of code away from the support you want, that is, subclass eg the HibernetDataSource, and in execute(), check oldValues.versionField against a newly fetched record (which you can achieve with new DSRequest().execute()).

        However if you'd prefer this were rolled into the product (for example, a property autoDetectConcurrentModification on a DataSource or operationBinding), we have the Feature Sponsorship process for that.

        Comment


          #5
          Thank you once again. I will keep on mind your recommendations.

          Regards
          Nikolay

          Comment


            #6
            I got to trying implementation of optimistic locking in a custom data source which extends SQLDataSource and hit a problem: update and remove operations seem to ignore criteria on fields other than the primary key. Is there a workaround for this? Here is my custom data source :
            Code:
            package com.sample.demo.server;
            
            import com.isomorphic.datasource.DSRequest;
            import com.isomorphic.datasource.DSResponse;
            import com.isomorphic.sql.SQLDataSource;
            
            public class CustomSQLDataSource
                extends SQLDataSource
            {
                @Override
                public DSResponse execute(DSRequest req)
                    throws Exception
                {
                    String operationType = req.getOperationType();
                    if ("update".equals(operationType)) {
                        return customUpdate(req);
                    }
                    else if ("remove".equals(operationType)) {
                        return customRemove(req);
                    }
                    return super.execute(req);
            
                }
            
                @SuppressWarnings("unchecked")
                private DSResponse customUpdate(DSRequest req)
                    throws Exception
                {
                    Object oldVersion = req.getOldValues().get("VERSION");
                    if (oldVersion != null && oldVersion instanceof Long) {
                        Long newVersion = new Long(((Long) oldVersion).longValue() + 1L);
                        req.getValues().put("VERSION", newVersion);
                        req.getCriteria().put("VERSION", oldVersion);
                    }
            
                    return super.execute(req);
                }
            
                @SuppressWarnings("unchecked")
                private DSResponse customRemove(DSRequest req)
                    throws Exception
                {
                    Object version = req.getOldValues().get("VERSION");
                    if (version != null && version instanceof Long) {
                        req.getCriteria().put("VERSION", version);
                    }
            
                    return super.execute(req);
                }
            }

            Comment


              #7
              That's a safety feature so that you don't accidentally wipe out the whole table if you have a bug where there's no criteria on a "remove". To disable it, use dsRequest.setAllowMultiUpdates().

              Comment


                #8
                Thank you very much for the help!

                For the benefit of eventual future readers here is a final version of my test data source class:
                Code:
                package com.sample.demo.server;
                
                import com.isomorphic.datasource.DSRequest;
                import com.isomorphic.datasource.DSResponse;
                import com.isomorphic.sql.SQLDataSource;
                
                public class SampleSQLDataSource
                    extends SQLDataSource
                {
                    private static final String VERSION_FIELD = "VERSION";
                
                    @Override
                    public DSResponse execute(DSRequest req)
                        throws Exception
                    {
                        String operationType = req.getOperationType();
                        if ("update".equals(operationType)) {
                            return customUpdate(req);
                        }
                        else if ("remove".equals(operationType)) {
                            return customRemove(req);
                        }
                        return super.execute(req);
                
                    }
                
                    @SuppressWarnings("unchecked")
                    private DSResponse customUpdate(DSRequest req)
                        throws Exception
                    {
                        Object oldVersion = req.getOldValues().get(VERSION_FIELD);
                        if ((oldVersion == null) || !(oldVersion instanceof Long)) {
                            return super.execute(req);
                        }
                
                        req.setAllowMultiUpdate(true);
                        Long newVersion = new Long(((Long) oldVersion).longValue() + 1L);
                        req.getValues().put(VERSION_FIELD, newVersion);
                        req.getCriteria().put(VERSION_FIELD, oldVersion);
                        DSResponse response = super.execute(req);
                        if (0 == response.getAffectedRows()) {
                            throw new Exception("Concurrent modification!");
                        }
                        return response;
                    }
                
                    @SuppressWarnings("unchecked")
                    private DSResponse customRemove(DSRequest req)
                        throws Exception
                    {
                        Object version = req.getOldValues().get(VERSION_FIELD);
                        if (version == null || !(version instanceof Long)) {
                            return super.execute(req);
                        }
                
                        req.setAllowMultiUpdate(true);
                        req.getCriteria().put(VERSION_FIELD, version);
                        DSResponse response = super.execute(req);
                        if (0 == response.getAffectedRows()) {
                            throw new Exception("Concurrent modification!");
                        }
                        return response;
                    }
                }

                Comment

                Working...
                X