Serg
Serg

Reputation: 958

Concurrency saving in GWT

Good day!

I tried to implement concurrency saving in the GWT 2.4. There is a user case:

  1. Users John and Jim open one entity to editing
  2. John saves his changes. All is OK.
  3. Jim saves his changes. System asked about overwrite

    a. Jim does not want to overwrite, system just refreshes entity at the page

    b. Otherwise, if Jim wants to save his changes, changes must be persisted and John's changes will be destroyed. (left only in the history of changes)

So I have problem with 3.b.

public void save(MyEntityProxy entity){
    MyRequest rContext = (MyRequest) driver.flush();
    MyProxy myEntity = (MyProxy) rContext.edit(entity);
    entitySave(rContext, (MyProxy) myEntity, false);
}

private void entitySave(MyRequest rContext, final MyProxy myEntity, boolean overwrite){
    GWT.log("SAVE ENTITY WITH NAME = " + myEntity.getName());
    rContext.persist(myEntity, entityVersion, overwrite)
    .fire(new Receiver<MyProxy>() {
        @Override
        public void onSuccess(MyProxy response) {
            goToModel();
        }
        @Override
        public void onFailure(ServerFailure error) {
            if(isConcurency(error)){
                entitySave((MyRequest)getNewRequestContext(), myEntity,true);
            }
        }
    });
}

/*This is a method from MyService for persisting*/
public MyProxy persist(MyProxy entity, Long version, boolean overwrite) {
    LOG.info("PERSISTS ENTITY  NAME=" + entity.getName());
    if(!overwrite && !checkVersionChanged(entity, version)){    
      System.out.println("RAISE CHANGED_BY_OTHER EXCEPTION");
      throw new RuntimeException(CHANGED_BY_OTHER.name());              
    }
    entity = getEntityManager().merge(entity);
    getEntityManager().flush();
    return entity;
}

isConcurrency is a method for checking concurrency issue and returns true when user choose “overwrite” point in the dialog.

GWT log:

SAVE ENTITY WITH NAME = John //There is John changed name of entity
SAVE ENTITY WITH NAME = Jim  //There is John changed name of entity
SAVE ENTITY WITH NAME = Jim  //There is John overwrites entity

Server Log:

[INFO] PERSISTS ENTITY NAME=Jim //There is John changed name of entity
[INFO] SAVE ENTITY NAME=Jim     //Persisting of John's changes. Here John finished his work
[INFO] PERSISTS ENTITY NAME=John //There is Jim changed name of entity
[INFO] RAISE CHANGED_BY_OTHER EXCEPTION   //Exception raises and dialog shows for Jim
[INFO] PERSISTS ENTITY NAME=John //Second iteration of saving. Look at the name!.

I do not understand what happened. When Jim overwrites his changes, at the client layer all is correct, but server layer works with data saved by previous user.

Is anybody knows how can I correctly overwrite changes in this situation?

Upvotes: 2

Views: 227

Answers (1)

Thomas Broyer
Thomas Broyer

Reputation: 64541

When you save to overwrite, you edit the same entity as you sent the first time around and which has then been frozen and then detached from the RequestContext. So, when you pass the entity to the newly created RequestContext, it implicitly edit()s it, and because there's no change applied to it, it then sends an empty diff to the server when fire()d. The server is thus asked to 1) load the entity from the database, 2) apply the diff (that is, do nothing, as the diff is empty) and then 3) save the entity, which at that point has not been modified since last persisted.

Ideally, you'd want to edit() the same entity as in the first request and re-apply the same changes to it, so you send the exact same diff to the server. There's unfortunately no easy way to do it (well, it depends who you put the edited data into your proxies).

See http://code.google.com/p/google-web-toolkit/issues/detail?id=5794 and http://code.google.com/p/google-web-toolkit/issues/detail?id=6046

Though clearly, RequestFactory is not tailored for these use cases, it's more about save without asking, with your application providing a way to undo the changes (e.g. logged on the server and assigned an ID).

Upvotes: 1

Related Questions