Уточнить как работают GWT RequestFactory и RequestContext

Я пытаюсь внедрить RequestFactory и среду Editor в мое приложение. Даже после изучения форума, форума разработчиков Google и других, я обнаружил, что есть что-то фундаментальное, чего я не понимаю в использовании RequestContext с RequestFactory. Вот мой сценарий:
У меня есть простой объект, который имеет три поля, идентификатор, версия, описание, называемое CmsObjectType. У меня есть соответствующий EntityProxy и CmsObjectTypeServiceDAO с моими операциями CRUD. Я также реализовал классы ServiceLocator и ObjectLocator. Этот код все компилируется и запускается.

Я также создал простой контрольный пример для проверки операций CRUD, используя следующее:

public class RequestFactoryProvider {

public static CmsRequestFactory get() {
    SimpleEventBus eventBus = new SimpleEventBus();
    CmsRequestFactory requestFactory = RequestFactoryMagic.create(CmsRequestFactory.class);
    ServiceLayer serviceLayer = ServiceLayer.create();

    SimpleRequestProcessor processor = new SimpleRequestProcessor(
            serviceLayer);
    requestFactory.initialize(eventBus, new InProcessRequestTransport(
            processor));
    return requestFactory;
}

}

Тест:

public class TestCmsObjectTypeRequest extends Assert {

private static CmsRequestFactory requestFactory;
private static CmsObjectTypeRequestContext objectTypeRequest;
private Long newId;

@Before
public void setUp() {
    requestFactory = RequestFactoryProvider.get();
    objectTypeRequest = requestFactory.objectTypeRequest();
}

    @Test
public void testEdit() {
    final CmsObjectTypeProxy newType = objectTypeRequest
            .create(CmsObjectTypeProxy.class);
    newType.setDescription("NEW TYPE");
    objectTypeRequest.persist(newType).to(new Receiver<Long>() {

        @Override
        public void onSuccess(Long response) {
            if (response != null) {
                newId = response;
                assertTrue(true);
            } else {
                fail();
            }
        }

        @Override
        public void onFailure(ServerFailure error) {
            fail();
        }
    });

    // Edit the newly created object
    newType.setDescription("EDITED NEW TYPE");

        objectTypeRequest.update(newType).to(new Receiver<Boolean>() {

            @Override
            public void onSuccess(Boolean response) {
                assertTrue(response);
            }

            @Override
            public void onFailure(ServerFailure error) {
                fail();
            }
        });

        //Remove it when we're done..
        objectTypeRequest.delete(newType).to(new Receiver<Boolean>() {

        @Override
        public void onSuccess(Boolean response) {
            System.out.println("onSuccess from delete.");
            assertTrue(response);
        }

        @Override
        public void onFailure(ServerFailure error) {
            fail();
        }
    });
    objectTypeRequest.fire();
}
}

Когда я создаю новый контекст запроса и объединяю в цепочку мои вызовы методов для создания, обновления и удаления, а затем вызываю fire(), это работает без проблем в тесте выше. Однако, если я пытаюсь сделать эти вызовы индивидуально, вызывая метод, а затем fire(), я сталкиваюсь с проблемами. Я могу вызвать create() с Receiver, возвращающим идентификатор вновь созданной сущности, а затем я использую этот идентификатор для вызова find (id) и получаю обратно вновь созданную сущность. До этого момента все работает нормально. Однако это то, где я запутался.. если я пытаюсь вызвать edit с текущим RequestContext в методе onSuccess() Receiver из find(id), я получаю сообщение об ошибке, сообщающее, что контекст уже выполняется. Если я создаю локальную переменную для foundProxy, а затем пытаюсь использовать новый экземпляр RequestContext для вызова requestContext.edit(foundProxy) для вновь найденного объекта, а затем вызываю update(), я получаю ошибку сервера, чаще всего: Ошибка сервера: Запрашиваемая сущность недоступна на сервере. Если я не создаю новый экземпляр контекста запроса, я получаю исключение IllegalStateException, сообщающее, что запрос уже выполняется. Вот пример теста, который, надеюсь, прояснит ситуацию:

@Test
public void testEditWOChaining() {
    final CmsObjectTypeProxy newType = objectTypeRequest
            .create(CmsObjectTypeProxy.class);
    newType.setDescription("NEW TYPE");
    objectTypeRequest.persist(newType).to(new Receiver<Long>() {

        @Override
        public void onSuccess(Long response) {
            if (response != null) {
                setNewId(response);
                assertTrue(true);
            } else {
                fail();
            }
        }

        @Override
        public void onFailure(ServerFailure error) {
            fail();
        }
    }).fire();

    if (newId != null) {
        objectTypeRequest = requestFactory.objectTypeRequest();
        objectTypeRequest.find(newId)
                .to(new Receiver<CmsObjectTypeProxy>() {

                    @Override
                    public void onSuccess(CmsObjectTypeProxy response) {
                        if (response != null) {
                            foundProxy = response;
                        }
                    }

                    @Override
                    public void onFailure(ServerFailure error) {
                        fail();
                    }
                }).fire();
    }

    if (foundProxy != null) {
        // Edit the newly created object
        objectTypeRequest = requestFactory.objectTypeRequest();
        CmsObjectTypeProxy editableProxy = objectTypeRequest
                .edit(foundProxy);
        editableProxy.setDescription("EDITED NEW TYPE");

        objectTypeRequest.update(editableProxy).to(new Receiver<Boolean>() {

            @Override
            public void onSuccess(Boolean response) {
                assertTrue(response);
            }

            @Override
            public void onFailure(ServerFailure error) {
                fail();
            }
        }).fire();
    }

    // Remove it when we're done..
    objectTypeRequest.delete(foundProxy).to(new Receiver<Boolean>() {

        @Override
        public void onSuccess(Boolean response) {
            System.out.println("onSuccess from delete.");
            assertTrue(response);
        }

        @Override
        public void onFailure(ServerFailure error) {
            fail();
        }
    });
    objectTypeRequest.fire();
}

Вот мои вопросы. Каков наилучший способ обработки редактирования, если оно связано не с create(), а с find()? Если я пытаюсь связать поиск с обновлением, мой foundProxy будет нулевым, и все не будет обновлено. Должны ли прокси оставаться привязанными к контексту, в котором они созданы, чтобы иметь возможность обновлять их? Если кто-то может объяснить, как это работает, или указать мне какую-то документацию, в которой указано, чего мне не хватает, я был бы признателен. Возможно ли это как-то связано с тем, как среда тестирования обрабатывает запросы? Я прочитал следующее, поэтому, если я что-то пропустил в них, пожалуйста, дайте мне знать: Отличное описание от tbroyer

Документы Google Любая помощь будет принята с благодарностью. Спасибо!

1 ответ

Решение

Посмотрите на RequestFactoryTestв исходном коде GWT для примеров. testChangedEdit() Метод похож на то, что вы пытаетесь написать. Это вызывает find() метод, а затем работает на возвращенном прокси в onSuccess() метод.

RequestContext не долгоживущий объект. Он действителен только с момента, когда он вызывается, когда вы звоните fire() в теме. Он может быть использован повторно, только если onFailure() или же onViolation() метод вызывается в вашем Receiver,

EntityProxy или же ValueProxy вернулся через Receiver.onSuccess() представляет собой снимок данных сервера. Таким образом, прокси-сервер является неизменным, если он не связан с RequestContext позвонив edit(), Прокси, возвращенные RequestContext.create() изменчивы Изменяемый прокси всегда связан только с одним RequestContext и это ошибка " пересекать потоки ". Это не ошибка re-edit() изменяемый прокси.

Причина, по которой он работает таким образом, заключается в том, что клиент RequestFactory может отправлять только дельты на сервер. Дельты применяются к долгоживущим объектам на сервере, вызывая объект домена find() метод (или с помощью Locator). RequestContext по сути является аккумулятором для proxy.setFoo() звонки и один или несколько Request / InstanceRequest вызовы.

Общие рекомендации:

  • Не храните экземпляры RequestContext в полях объектов, время жизни которых превышает fire() вызов метода.
  • Точно так же редактируемый EntityProxy или же ValueProxy экземпляры не должны быть сохранены после вызова fire(),
  • EntityProxyId вернулся из EntityProxy.stableId() может быть сохранен на неопределенный срок, даже от вновь созданного прокси. stableId объект подходит для использования в качестве ключа в Map объекты и имеет стабильную семантику идентификации объекта (т.е. два снимка одного и того же объекта домена сервера с разными версиями будут возвращать один и тот же EntityProxyId).
  • Экземпляры RequestFactory должен быть построен один раз и сохранен на весь срок службы модуля, так как они имеют нетривиальную стоимость строительства.
Другие вопросы по тегам