阐明 GWT RequestFactory 和 RequestContext 如何工作
我正在尝试将 RequestFactory 和编辑器框架实现到我的应用程序中。即使在研究了论坛、Google 开发者论坛和其他论坛之后,我仍然发现,关于将 RequestContext 与 RequestFactory 一起使用,我仍然不明白一些基本的东西。这是我的场景:
我有一个简单的实体,它具有三个字段,id、版本、描述,称为 CmsObjectType。我有一个相应的 EntityProxy 和一个带有 CRUD 操作的 CmsObjectTypeServiceDAO。我还实现了 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() ,让接收者返回新创建的实体的 id,然后使用该 id 调用 find(id) 并取回新创建的实体。到目前为止一切正常。然而,这就是我感到困惑的地方..如果我尝试从 find(id) 的接收器的 onSuccess() 方法中使用当前的 RequestContext 调用编辑,我会收到一条错误消息,指出上下文已经在进行中。如果我为 findProxy 创建一个局部变量,然后尝试使用 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 文档 任何帮助将不胜感激。谢谢你!
I am trying to implement RequestFactory and the Editor framework into my app. I'm finding even after researching the forum, the Google Developer forum, and others that there is something fundamental that I don't understand about using RequestContext with RequestFactory. Here is my scenario:
I have a simple Entity that has three fields, id, version, description called CmsObjectType. I have a corresponding EntityProxy and an CmsObjectTypeServiceDAO with my CRUD operations. I have also implemented ServiceLocator and ObjectLocator classes. This code all compiles and runs.
I have also created a simple test case to test the CRUD operations, using the following:
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;
}
}
The Test:
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();
}
}
When I create a new request context and chain my method calls for create, update, and delete and then call fire(), it works with no problems in the test above. However if I try to do these calls individually by calling the method and then fire() I run into problems. I can call create() with the Receiver returning the id of the newly created entity and then I use that id to call find(id) and I get back the newly created entity. Up to this point everything works ok. However, this is where I am confused.. if I try to call edit with the current RequestContext within the Receiver's onSuccess() method from the find(id), I get an error saying the context is already in progress. If I create a local variable for the foundProxy and then try to use a new instance of RequestContext to call requestContext.edit(foundProxy) on the newly found entity and then call update() I get a server error, most commonly: Server Error: The requested entity is not available on the server. If I don't create the new instance of request context I get an IllegalStateException saying the request is already in progress.
Here is the sample test that hopefully will make this clearer:
@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();
}
Here are my questions.. What is the best way to handle an edit if it is not associated with a create() but with a find()? If I try to chain the find with an update my foundProxy is null and things don't update. Do proxies have to stay bound to the context in which they are created in order to be able to perform updates on them? If someone could explain how this works or point me to some documentation that points out what I am missing I would be grateful. Is it possible this is something to do with the way the testing framework processes the requests?
I have read the following so if I missed something in them please let me know:
Great description by tbroyer
Google docs
Any help would be greatly appreciated. Thank you!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
查看
RequestFactoryTest
。testChangedEdit()
方法与您尝试编写的方法类似。它调用find()
方法,然后在onSuccess()
方法中对返回的代理进行操作。RequestContext
不是一个长期存在的对象。它仅从调用它的时间到您对其调用fire()
期间有效。仅当在Receiver
中调用onFailure()
或onViolation()
方法时,才可以重复使用它。通过 Receiver.onSuccess() 返回的 EntityProxy 或 ValueProxy 表示服务器数据的快照。因此,代理是不可变的,除非它通过调用
edit()
与RequestContext
关联。RequestContext.create()
返回的代理是可变的。可变代理始终与一个RequestContext
关联,并且“它以这种方式工作的原因是允许 RequestFactory 客户端仅将增量发送到服务器。通过调用域对象的
find()
方法(或使用Locator
),将增量应用于服务器上的长期实体。 RequestContext 本质上是一个用于proxy.setFoo()
调用和一个或多个Request
/InstanceRequest
调用的累加器。一般准则:
fire()
方法调用生命周期的对象字段中。EntityProxy
或ValueProxy
实例不应在调用fire()
之外保留。EntityProxy.stableId()
返回的EntityProxyId
可以无限期保留,即使是从新创建的代理中也是如此。stableId
对象适合用作Map
对象中的键,并且具有稳定的对象标识语义(即具有不同版本的同一服务器域对象的两个快照将返回相同的“EntityProxyId”)。RequestFactory
的实例应该构造一次并在模块的生命周期内保留,因为它们的构造成本不菲。Take a look at the
RequestFactoryTest
in the GWT source code for examples. ThetestChangedEdit()
method is similar to what you're trying to write. It calls afind()
method and then operates on the returned proxy in theonSuccess()
method.A
RequestContext
isn't a long-lived object. It is only valid from the time that it is called to when you callfire()
on it. It can be re-used only if theonFailure()
oronViolation()
method is called in yourReceiver
.An
EntityProxy
orValueProxy
returned viaReceiver.onSuccess()
represents a snapshot of server data. Thus, the proxy is immutable unless it is associated with aRequestContext
by callingedit()
. The proxies returned byRequestContext.create()
are mutable. A mutable proxy is always associated with exactly oneRequestContext
and it is an error to "cross the streams." It is not an error tore-edit()
a mutable proxy.The reason it works this way is to allow the RequestFactory client to only send deltas to the server. The deltas are applied to the long-lived entities on the server by calling the domain object's
find()
method (or using aLocator
). The RequestContext is essentially an accumulator forproxy.setFoo()
calls and one or moreRequest
/InstanceRequest
invocations.General guidelines:
fire()
method invocation.EntityProxy
orValueProxy
instances should not be retained beyond the call tofire()
.EntityProxyId
returned fromEntityProxy.stableId()
can be retained indefinitely, even from a newly-created proxy. ThestableId
object is suitable for use as the key inMap
objects and has stable object-identity semantics (i.e. two snapshots of the same server domain object with different versions would return the same `EntityProxyId').RequestFactory
should be constructed once and retained for the lifetime of the module, since they have non-trivial construction cost.