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