Поддерживает ли GWT RequestFactory реализацию оптимистичного управления параллелизмом? - PullRequest
2 голосов
/ 08 октября 2011

В приложении GWT я представляю элементы, которые могут редактировать пользователи.Загрузка и сохранение элементов выполняется с помощью фабрики запросов GWT.Теперь я хочу добиться того, чтобы два пользователя одновременно редактировали элемент, который первым сохраняет пользователь, который сохраняет оптимистичный контроль параллелизма.Это означает, что когда второй пользователь сохраняет свои изменения, бэкэнд фабрики запросов распознает, что версия или наличие элемента, хранящегося в бэкэнде, изменились, поскольку он был передан клиенту, а фабрика / бэкэнд запросов затем каким-то образом препятствует обновлению элементов/saved.

Я попытался реализовать это в методе службы, который используется для сохранения элементов, но это не сработает, поскольку фабрика запросов передает элементы, только что полученные из серверной части, с внесенными изменениями пользователя, означающими версииэти пункты являются текущими версиями из бэкэнда и бессмысленным сравнением.

Есть ли какие-либо хуки в обработке фабрики запросов, которые я могу использовать для достижения запрошенного поведения?Есть другие идеи?Или я должен вместо этого использовать GWT-RPC ...

Ответы [ 2 ]

3 голосов
/ 08 октября 2011

Нет: http://code.google.com/p/google-web-toolkit/issues/detail?id=6046

До тех пор, пока предложенный API не будет реализован (EntityLocator, в комментарии № 1, но мне не ясно, как информация о версии может быть восстановлена ​​из ее сериализованной форма), вам придется каким-то образом отправить версию обратно на сервер.
Как я уже говорил в этом выпуске, этого нельзя сделать, просто сделав свойство version доступным в прокси-сервере и установив его;но вы можете добавить другое свойство: его получение всегда будет возвращать null (или аналогичное несуществующее значение), так что установка его на стороне клиента в значение свойства "true" версии всегда будет производитьизменение, которое гарантирует, что значение будет отправлено на сервер как часть «свойства diff»;и на стороне сервера вы могли бы обрабатывать вещи либо в установщике (когда RequestFactory применяет «свойство diff» и вызывает установщик, если значение отличается от «истинной» версии, тогда генерировать исключение), либо в службеметоды (сравните версию, отправленную с клиента - которую вы получите от получателя, отличного от того, который отображен на клиенте, так как он всегда должен возвращать null - в «истинную» версию объекта, и поднимитеошибка, если они не совпадают).

Что-то вроде:

@ProxyFor(MyEntity.class)
interface MyEntityProxy extends EntityProxy {
   String getServerVersion();
   String getClientVersion();
   void setClientVersion(String clientVersion);
   …
}

@Entity
class MyEntity {
   private String clientVersion;
   @Version private String serverVersion;

   public String getServerVersion() { return serverVersion; }
   public String getClientVersion() { return null; }
   public void setClientVersion(String clientVersion) {
      this.clientVersion = clientVersion;
   }

   public void checkVersion() {
      if (Objects.equal(serverVersion, clientVersion)) {
         throw new OptimisticConcurrencyException();
      }
   }
}

Обратите внимание, что я не проверял это, это чистая теория.

2 голосов
/ 08 мая 2012

Мы придумали еще один обходной путь для оптимистичной блокировки в нашем приложении. Поскольку версию нельзя передать с помощью самого прокси-сервера (, как объяснил Томас ), мы передаем ее через параметр HTTP GET фабрике запросов.

На клиенте:

MyRequestFactory factory = GWT.create( MyRequestFactory.class );
RequestTransport transport = new DefaultRequestTransport() {
        @Override
        public String getRequestUrl() {
            return super.getRequestUrl() + "?version=" + getMyVersion();
        }
    };
factory.initialize(new SimpleEventBus(), transport);

На сервере мы создаем ServiceLayerDecorator и читаем версию из RequestFactoryServlet.getThreadLocalRequest():

public static class MyServiceLayerDecorator extends ServiceLayerDecorator {
  @Override
  public final <T> T loadDomainObject(final Class<T> clazz, final Object domainId) {
    HttpServletRequest threadLocalRequest = RequestFactoryServlet.getThreadLocalRequest();
    String clientVersion = threadLocalRequest.getParameter("version") );

    T domainObject = super.loadDomainObject(clazz, domainId);
    String serverVersion = ((HasVersion)domainObject).getVersion();

    if ( versionMismatch(serverVersion, clientVersion) )
      report("Version error!");         

    return domainObject;
  }
}

Преимущество состоит в том, что loadDomainObject() вызывается до того, как RF-объект применяет к объекту домена любые изменения.

В нашем случае мы просто отслеживаем одну сущность, поэтому используем одну версию, но подход можно распространить на несколько сущностей.

...