2011-04-12 3 views
5

RequestFactory 및 Editor 프레임 워크를 구현하려고합니다. 나는 RequestFactory와 함께 RequestContext를 사용하는 것에 대해 이해할 수없는 근본적인 것이 있다는 포럼, Google 개발자 포럼 및 다른 것들을 연구 한 후에도 찾아 보았습니다. 여기 내 시나리오는 다음과 같습니다.
CmsObjectType이라는 ID, 버전, 설명이라는 세 개의 필드가있는 간단한 엔티티가 있습니다. 내 CRUD 작업과 함께 해당 EntityProxy 및 CmsObjectTypeServiceDAO가 있습니다. 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()를 호출하면 문제가 발생합니다. 새롭게 생성 된 엔티티의 ID를 반환하는 Receiver로 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가 null이고 모든 항목이 업데이트되지 않습니다. 프록시는 업데이트를 수행하기 위해 생성 된 컨텍스트에 바인딩되어 있어야합니까? 누군가가 어떻게 작동하는지 설명 할 수 있거나 제가 누락 된 것을 지적하는 문서를 지적하면 감사 할 것입니다. 이것은 테스트 프레임 워크가 요청을 처리하는 방식과 관련이있을 수 있습니까? 내가 알려 주시기 바랍니다 그들에게 뭔가를 놓친 그래서 만약 내가 다음을 읽고 : Great description by tbroyer

Google docs 어떤 도움을 주시면 감사하겠습니다. 고맙습니다!

답변

18

예를 들어 GWT 소스 코드에서 RequestFactoryTest을 살펴보십시오. testChangedEdit() 방법은 작성하려는 것과 비슷합니다. find() 메서드를 호출하고 onSuccess() 메서드에서 반환 된 프록시에서 작동합니다.

RequestContext은 수명이 긴 개체가 아닙니다. fire()을 호출 할 때까지 호출 된 이후에만 유효합니다. Receiver에서 onFailure() 또는 onViolation() 메서드가 호출 된 경우에만 다시 사용할 수 있습니다.

Receiver.onSuccess()을 통해 반송 된 EntityProxy 또는 ValueProxy은 서버 데이터의 스냅 샷을 나타냅니다. 따라서 프록시는 edit()을 호출하여 RequestContext과 연결되어 있지 않으면 변경할 수 없습니다. RequestContext.create()에 의해 반환 된 프록시는 변경할 수 있습니다. 변경 가능한 프록시는 항상 정확히 하나의 RequestContext과 연결되며 "cross the streams"에 대한 오류입니다. 변경 가능한 프록시 인 re-edit()에는 오류가 없습니다.

이 방법으로 작동하는 이유는 RequestFactory 클라이언트가 델타 만 서버로 보낼 수있게하기 위해서입니다. 델타는 도메인 오브젝트의 find() 메소드 (또는 Locator 사용)를 호출하여 서버의 수명이 긴 엔티티에 적용됩니다. RequestContext는 기본적으로 proxy.setFoo() 호출에 대한 누적 계산기이고 하나 이상은 Request/InstanceRequest 호출입니다.

일반 지침 :

  • 는 평생 그 fire() 메소드 호출의 초과 객체의 필드에 RequestContext 인스턴스를 보관하지 마십시오.
  • 비슷하게 편집 가능한 EntityProxy 또는 ValueProxy 인스턴스는 fire() 호출 이후로 유지하면 안됩니다.
  • EntityProxyIdEntityProxy.stableId()에서 새로 생성 된 프록시에서도 무기한으로 보존 될 수 있습니다. stableId 객체는 Map 객체의 키로 사용하기에 적합하며 안정적인 객체 식별 의미 (즉, 동일한 버전의 동일한 서버 도메인 객체의 두 스냅 샷은 동일한 'EntityProxyId'를 반환합니다)가 있습니다.
  • RequestFactory의 인스턴스는 건설 비용이 적기 때문에 한 번 구성하고 모듈 수명 동안 유지해야합니다.
+0

명확하고 간결한 답변을 주셔서 감사합니다.하지만 문제가 될 수있는 또 다른 질문이 있습니다. Locator를 확장하는 ObjectLocator 클래스가 있습니다. 내 질문은 내가 재정의하는 find (clazz, id) 메서드에 관한 것입니다. Google App Engine 데이터 저장소 api를 사용하는 Objectify를 사용한 예를 보았습니다.이 객체는 서버 측 객체에 대한 캐싱 메커니즘 인 것으로 보입니다. 객체를 가져 오기 위해 데이터베이스 호출을 만드는 또 다른 예제를 보았습니다. 여기서 무엇을 반환해야합니까? 서버 객체를 가져 오기 위해 데이터베이스 호출 또는 캐싱 메커니즘을 구현해야합니까? – mcfar

+0

개체를 캐싱하거나 새로운 개체를 호출하는 것은 응용 프로그램에서 예상하는 동시성 수준에 따라 다릅니다. 객체가 불변 인 경우, 캐싱 인스턴스는 의미가 있습니다. AppEngine에 대해 기억해야 할 점은 요청이 애플리케이션 인스턴스간에 수신 거부 될 수 있다는 점입니다. 내 제안은 작동하는 가장 단순한 것을 작성한 다음 성능 문제가 아닌지 결정했다면 반복합니다. – BobV

+0

안녕하세요. DynaTableRf 샘플은 특히 RequestContext와 프록시 객체의 유지와 관련하여 가이드 라인 중 일부를 적용하지 않는 것으로 보입니다. 또는 DynaTableRf가 어떻게 작동하는지 오해 한 적이 있습니까? DynaTableRf를 우수 사례로 간주합니까? 아니면 다른 곳을 찾아야합니까? – David

관련 문제