2011-04-12 84 views
5

我想实现RequestFactory和编辑器框架到我的应用程序。即使在研究论坛,Google开发者论坛和其他人之后,我也发现有一些基本的东西我不明白在RequestFactory中使用RequestContext。这是我的场景:
我有一个简单的实体,有三个字段,id,版本,描述称为CmsObjectType。我有一个相应的EntityProxy和一个CmsObjectTypeServiceDAO与我的CRUD操作。我也实现了ServiceLocator和ObjectLocator类。此代码全部编译并运行。澄清如何GWT RequestFactory和RequestContext工作

我还创建了一个简单的测试用例来测试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(),则会遇到问题。我可以使用Receiver返回新创建的实体的ID来调用create(),然后使用该ID调用find(id),并返回新创建的实体。到目前为止,一切正常。然而,这是我困惑的地方..如果我尝试从find(id)的Receiver的onSuccess()方法中使用当前的RequestContext调用编辑,我会收到一个错误,说上下文已经在进行中。如果我为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(); 
} 

这里是我的问题。什么是处理编辑,如果它不与创建(关联的最好方式),但一个发现( )?如果我尝试将查找与更新链接起来,那么我的foundProxy为空,而事情不会更新。代理必须保持绑定到创建它们的上下文,以便能够对它们执行更新?如果有人可以解释这是如何工作的或指向我的一些文件,指出我错过了什么,我将不胜感激。这可能与测试框架处理请求的方式有关吗? 我已阅读以下,所以如果我错过了他们的东西,请让我知道: Great description by tbroyer

Google docs 任何帮助将不胜感激。谢谢!

回答

18

查看GWT源代码中的RequestFactoryTest示例。 testChangedEdit()方法与您要编写的内容类似。它调用find()方法,然后在onSuccess()方法中对返回的代理进行操作。

A RequestContext不是一个长寿命的对象。它只有在你打电话给fire()的时候才有效。只有在您的Receiver中调用onFailure()onViolation()方法时才可以重复使用。

通过Receiver.onSuccess()返回的EntityProxyValueProxy表示服务器数据的快照。因此,代理是不可变的,除非它通过调用edit()RequestContext相关联。由RequestContext.create()返回的代理是可变的。一个可变代理总是与一个RequestContext关联,这是“cross the streams”的错误。 re-edit()是一个可变代理,这不是一个错误。

是这样工作的原因是为了让RequestFactory客户端只发送增量到服务器。通过调用域对象的find()方法(或使用Locator),将增量应用于服务器上的长寿命实体。 RequestContext本质上是一个累加器,用于调用proxy.setFoo()调用和一个或多个Request/InstanceRequest调用。

一般准则:

  • RequestContext的情况下,不要存放在对象的生命周期超过了fire()方法调用的领域。
  • 同样,编辑EntityProxyValueProxy情况下,不应该被保留到调用fire()
  • EntityProxyIdEntityProxy.stableId()返回可以无限期保留,即使是从新创建的代理。 stableId对象适合用作Map对象中的键,并具有稳定的对象标识语义(即具有不同版本的相同服务器域对象的两个快照将返回相同的`EntityProxyId')。的RequestFactory
  • 实例应当被构造一次,并保留用于模块的寿命,因为它们具有非平凡的建设成本。
+0

谢谢您的清晰,简洁的答案,但是它会导致另一个问题,可能是我的问题的一部分。我有一个扩展Locator的ObjectLocator类。我的问题是关于我重写的find(clazz,id)方法。我见过一个使用Objectify的例子,它使用Google App Engine数据存储区api,这似乎是服务器端对象的缓存机制。我看到了另一个使数据库调用来获取对象的例子。我应该回到这里,我是否需要进行数据库调用或实现缓存机制来获取服务器对象? – mcfar 2011-04-13 16:23:26

+0

缓存对象或调用新对象取决于您在应用程序中期望的并发级别。如果对象是不可变的,那么缓存实例是有道理的。要记住AppEngine的一点是请求会在应用程序的实例之间弹跳。我的建议是编写最简单的工作,然后在确定某件事情是或不是性能问题后进行迭代。 – BobV 2011-04-13 18:54:06

+0

嗨,鲍勃。在我看来,DynaTableRf示例并不适用您的一些准则,特别是在保留RequestContext和代理对象方面;或者我误解了DynaTableRf的工作原理?你认为DynaTableRf是一个好习惯的例子,还是我应该去寻找另一个? – David 2011-06-10 07:06:35