2011-04-12 81 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