阐明 GWT RequestFactory 和 RequestContext 如何工作

发布于 2024-11-01 01:49:36 字数 6010 浏览 4 评论 0原文

我正在尝试将 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怎言笑 2024-11-08 01:49:36

查看RequestFactoryTesttestChangedEdit() 方法与您尝试编写的方法类似。它调用 find() 方法,然后在 onSuccess() 方法中对返回的代理进行操作。

RequestContext 不是一个长期存在的对象。它仅从调用它的时间到您对其调用 fire() 期间有效。仅当在 Receiver 中调用 onFailure()onViolation() 方法时,才可以重复使用它。

通过 Receiver.onSuccess() 返回的 EntityProxy 或 ValueProxy 表示服务器数据的快照。因此,代理是不可变的,除非它通过调用 edit()RequestContext 关联。 RequestContext.create() 返回的代理是可变的。可变代理始终与一个 RequestContext 关联,并且“

它以这种方式工作的原因是允许 RequestFactory 客户端仅将增量发送到服务器。通过调用域对象的 find() 方法(或使用 Locator),将增量应用于服务器上的长期实体。 RequestContext 本质上是一个用于 proxy.setFoo() 调用和一个或多个 Request / InstanceRequest 调用的累加器。

一般准则:

  • 不要将 RequestContext 实例存储在生命周期超过 fire() 方法调用生命周期的对象字段中。
  • 同样,可编辑的 EntityProxyValueProxy 实例不应在调用 fire() 之外保留。
  • EntityProxy.stableId() 返回的 EntityProxyId 可以无限期保留,即使是从新创建的代理中也是如此。 stableId 对象适合用作 Map 对象中的键,并且具有稳定的对象标识语义(即具有不同版本的同一服务器域对象的两个快照将返回相同的“EntityProxyId”)。
  • RequestFactory 的实例应该构造一次并在模块的生命周期内保留,因为它们的构造成本不菲。

Take a look at the RequestFactoryTest in the GWT source code for examples. The testChangedEdit() method is similar to what you're trying to write. It calls a find() method and then operates on the returned proxy in the onSuccess() method.

A RequestContext isn't a long-lived object. It is only valid from the time that it is called to when you call fire() on it. It can be re-used only if the onFailure() or onViolation() method is called in your Receiver.

An EntityProxy or ValueProxy returned via Receiver.onSuccess() represents a snapshot of server data. Thus, the proxy is immutable unless it is associated with a RequestContext by calling edit(). The proxies returned by RequestContext.create() are mutable. A mutable proxy is always associated with exactly one RequestContext and it is an error to "cross the streams." It is not an error to re-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 a Locator). The RequestContext is essentially an accumulator for proxy.setFoo() calls and one or more Request / InstanceRequest invocations.

General guidelines:

  • Don't store RequestContext instances in fields of objects whose lifetime exceeds that of the fire() method invocation.
  • Similarly, editable EntityProxy or ValueProxy instances should not be retained beyond the call to fire().
  • The EntityProxyId returned from EntityProxy.stableId() can be retained indefinitely, even from a newly-created proxy. The stableId object is suitable for use as the key in Map 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').
  • Instances of RequestFactory should be constructed once and retained for the lifetime of the module, since they have non-trivial construction cost.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文