Уточнить как работают GWT RequestFactory и RequestContext - PullRequest
5 голосов
/ 13 апреля 2011

Я пытаюсь внедрить 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 Ответ

18 голосов
/ 13 апреля 2011

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

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

вызван метод onFailure() или onViolation(). 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 должны создаваться один раз и сохраняться в течение всего срока службы модуля, поскольку они имеют нетривиальные затраты на создание.
...