Add ServerFailure.getRequestContext().
Provide getters for Request -> RequestContext -> RequestFactory ->
RequestTransport.
Add fakes for modified interfaces.
Issue 6469.
Review at http://gwt-code-reviews.appspot.com/1451815/
Patch by: bobv
Review by: rjrjr
Suggested by: jasonhall


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10316 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/Request.java b/user/src/com/google/web/bindery/requestfactory/shared/Request.java
index 5ad763d..e763440 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/Request.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/Request.java
@@ -16,9 +16,14 @@
 package com.google.web.bindery.requestfactory.shared;
 
 /**
- * Implemented by the request objects created by this factory.
+ * A Request represents a single method invocation on the server. It
+ * encapsulates the arguments provided to the Request factory method declared in
+ * a RequestContext as well as a set of object paths to return from the server.
+ * The returned data is provided to an optional {@link Receiver} object,
+ * specified by the {@link #to(Receiver)} method.
  * 
  * @param <T> The return type of objects in the corresponding response.
+ * @see com.google.web.bindery.requestfactory.shared.testing.FakeRequest
  */
 public interface Request<T> {
 
@@ -36,6 +41,11 @@
   void fire(Receiver<? super T> receiver);
 
   /**
+   * Returns the RequestContext associated with the Request.
+   */
+  RequestContext getRequestContext();
+
+  /**
    * Specify the object that will receive the result of the method invocation.
    * 
    * @param receiver a {@link Receiver} instance
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/RequestContext.java b/user/src/com/google/web/bindery/requestfactory/shared/RequestContext.java
index 72062c5..a9175b9 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/RequestContext.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/RequestContext.java
@@ -91,6 +91,11 @@
   void fire(Receiver<Void> receiver);
 
   /**
+   * Returns the {@link RequestFactory} that created the RequestContext.
+   */
+  RequestFactory getRequestFactory();
+
+  /**
    * Returns true if any changes have been made to proxies mutable under this
    * context. Note that vacuous changes &mdash; e.g. foo.setName(foo.getName()
    * &mdash; will not trip the changed flag. Similarly, "unmaking" a change will
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/RequestFactory.java b/user/src/com/google/web/bindery/requestfactory/shared/RequestFactory.java
index fd0f2f9..e1873b4 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/RequestFactory.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/RequestFactory.java
@@ -40,6 +40,7 @@
  * supertypes of value types is not supported (e.g. Object, Enum, Number).
  * </p>
  * 
+ * @see com.google.web.bindery.requestfactory.shared.testing.FakeRequestFactory
  * @see com.google.web.bindery.requestfactory.server.testing.InProcessRequestTransport
  */
 public interface RequestFactory {
@@ -118,6 +119,13 @@
   <T extends EntityProxy> EntityProxyId<T> getProxyId(String historyToken);
 
   /**
+   * Returns the RequestTransport set via {@link #initialize}.
+   * 
+   * @return the {@link RequestTransport} associated with this instance
+   */
+  RequestTransport getRequestTransport();
+
+  /**
    * Returns a ProxySerializer that can encode and decode the various
    * EntityProxy and ValueProxy types reachable from the RequestFactory.
    * 
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/RequestTransport.java b/user/src/com/google/web/bindery/requestfactory/shared/RequestTransport.java
index 4346f61..8cbec6a 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/RequestTransport.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/RequestTransport.java
@@ -20,6 +20,7 @@
  * payload to the backend.
  * 
  * @see com.google.web.bindery.requestfactory.gwt.client.DefaultRequestTransport
+ * @see com.google.web.bindery.requestfactory.shared.testing.FakeRequestTransport
  */
 public interface RequestTransport {
   /**
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/ServerFailure.java b/user/src/com/google/web/bindery/requestfactory/shared/ServerFailure.java
index a4b3e56..3106483 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/ServerFailure.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/ServerFailure.java
@@ -27,6 +27,7 @@
   private final String stackTraceString;
   private final String exceptionType;
   private final boolean fatal;
+  private RequestContext requestContext;
 
   /**
    * Constructs a ServerFailure with null properties.
@@ -75,6 +76,13 @@
   }
 
   /**
+   * Returns the RequestContext that triggered the ServerFailure.
+   */
+  public RequestContext getRequestContext() {
+    return requestContext;
+  }
+
+  /**
    * Return the failure stack trace.
    * 
    * @return the stack trace as a String
@@ -92,4 +100,11 @@
   public boolean isFatal() {
     return fatal;
   }
+
+  /**
+   * Sets the RequestContext to return via {@link #getRequestContext()}.
+   */
+  public void setRequestContext(RequestContext requestContext) {
+    this.requestContext = requestContext;
+  }
 }
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequest.java b/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequest.java
index 0a83bdc..ea36479 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequest.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequest.java
@@ -36,8 +36,7 @@
  * 
  * @param <T> return type
  */
-public abstract class AbstractRequest<T> implements Request<T>,
-    InstanceRequest<BaseProxy, T> {
+public abstract class AbstractRequest<T> implements Request<T>, InstanceRequest<BaseProxy, T> {
 
   /**
    * Used by generated subtypes.
@@ -67,6 +66,11 @@
     return Collections.unmodifiableSet(propertyRefs);
   }
 
+  @Override
+  public RequestContext getRequestContext() {
+    return requestContext;
+  }
+
   public RequestData getRequestData() {
     if (requestData == null) {
       requestData = makeRequestData();
@@ -119,8 +123,9 @@
     // The user may not have called to()
     if (receiver != null) {
       @SuppressWarnings("unchecked")
-      T result = (T) EntityCodex.decode(requestContext,
-          requestData.getReturnType(), requestData.getElementType(), split);
+      T result =
+          (T) EntityCodex.decode(requestContext, requestData.getReturnType(), requestData
+              .getElementType(), split);
       receiver.onSuccess(result);
     }
   }
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequestContext.java b/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequestContext.java
index 912c62b..c7bc3f0 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequestContext.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/impl/AbstractRequestContext.java
@@ -661,6 +661,7 @@
    */
   protected void fail(Receiver<Void> receiver, ServerFailure failure) {
     reuse();
+    failure.setRequestContext(this);
     Set<Throwable> causes = null;
     for (AbstractRequest<?> request : new ArrayList<AbstractRequest<?>>(state.invocations)) {
       try {
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequest.java b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequest.java
new file mode 100644
index 0000000..dbc204c
--- /dev/null
+++ b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.web.bindery.requestfactory.shared.testing;
+
+import com.google.web.bindery.requestfactory.shared.Receiver;
+import com.google.web.bindery.requestfactory.shared.Request;
+import com.google.web.bindery.requestfactory.shared.RequestContext;
+
+/**
+ * A no-op implementation of Request that can be used as a base type for writing
+ * unit tests.
+ * 
+ * @param <T> The return type of objects in the corresponding response.
+ */
+public class FakeRequest<T> implements Request<T> {
+
+  /**
+   * No-op.
+   */
+  @Override
+  public void fire() {
+  }
+
+  /**
+   * No-op.
+   */
+  @Override
+  public void fire(Receiver<? super T> receiver) {
+  }
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public RequestContext getRequestContext() {
+    return null;
+  }
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public RequestContext to(Receiver<? super T> receiver) {
+    return null;
+  }
+
+  /**
+   * Returns {@code this}.
+   */
+  @Override
+  public Request<T> with(String... propertyRefs) {
+    return this;
+  }
+}
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestContext.java b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestContext.java
index 5194fcb..4549951 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestContext.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestContext.java
@@ -21,6 +21,7 @@
 import com.google.web.bindery.requestfactory.shared.Receiver;
 import com.google.web.bindery.requestfactory.shared.Request;
 import com.google.web.bindery.requestfactory.shared.RequestContext;
+import com.google.web.bindery.requestfactory.shared.RequestFactory;
 
 /**
  * A no-op implementation of RequestConext that can be used as a base type for
@@ -75,6 +76,14 @@
   }
 
   /**
+   * Returns {@code null}.
+   */
+  @Override
+  public RequestFactory getRequestFactory() {
+    return null;
+  }
+
+  /**
    * Always returns {@code false}.
    */
   @Override
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestFactory.java b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestFactory.java
new file mode 100644
index 0000000..ddd07f5
--- /dev/null
+++ b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestFactory.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.web.bindery.requestfactory.shared.testing;
+
+import com.google.web.bindery.event.shared.EventBus;
+import com.google.web.bindery.requestfactory.shared.EntityProxy;
+import com.google.web.bindery.requestfactory.shared.EntityProxyId;
+import com.google.web.bindery.requestfactory.shared.ProxySerializer;
+import com.google.web.bindery.requestfactory.shared.ProxyStore;
+import com.google.web.bindery.requestfactory.shared.Request;
+import com.google.web.bindery.requestfactory.shared.RequestFactory;
+import com.google.web.bindery.requestfactory.shared.RequestTransport;
+
+/**
+ * A no-op implementation of {@link RequestFactory} that can be used for
+ * building mocks.
+ */
+public class FakeRequestFactory implements RequestFactory {
+
+  private EventBus eventBus;
+  private RequestTransport requestTransport;
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public <P extends EntityProxy> Request<P> find(EntityProxyId<P> proxyId) {
+    return null;
+  }
+
+  /**
+   * Returns the last value passed to
+   * {@link #initialize(EventBus, RequestTransport)}.
+   */
+  @Override
+  public EventBus getEventBus() {
+    return eventBus;
+  }
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public String getHistoryToken(Class<? extends EntityProxy> clazz) {
+    return null;
+  }
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public String getHistoryToken(EntityProxyId<?> proxy) {
+    return null;
+  }
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public Class<? extends EntityProxy> getProxyClass(String historyToken) {
+    return null;
+  }
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public <T extends EntityProxy> EntityProxyId<T> getProxyId(String historyToken) {
+    return null;
+  }
+
+  /**
+   * Returns the last value passed to
+   * {@link #initialize(EventBus, RequestTransport)}.
+   */
+  @Override
+  public RequestTransport getRequestTransport() {
+    return requestTransport;
+  }
+
+  /**
+   * Returns {@code null}.
+   */
+  @Override
+  public ProxySerializer getSerializer(ProxyStore store) {
+    return null;
+  }
+
+  /**
+   * Equivalent to {@code initialize(eventBus, new FakeRequestTransport())}.
+   */
+  @Override
+  public void initialize(EventBus eventBus) {
+    initialize(eventBus, new FakeRequestTransport());
+  }
+
+  /**
+   * Saves the parameters for later retrieval.
+   */
+  @Override
+  public void initialize(EventBus eventBus, RequestTransport transport) {
+    this.eventBus = eventBus;
+    this.requestTransport = transport;
+  }
+}
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestTransport.java b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestTransport.java
new file mode 100644
index 0000000..bb40eb6
--- /dev/null
+++ b/user/src/com/google/web/bindery/requestfactory/shared/testing/FakeRequestTransport.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.web.bindery.requestfactory.shared.testing;
+
+import com.google.web.bindery.requestfactory.shared.RequestTransport;
+
+/**
+ * A no-op implementation of {@link RequestTransport} that can be used for unit
+ * testing.
+ */
+public class FakeRequestTransport implements RequestTransport {
+  /**
+   * No-op.
+   */
+  @Override
+  public void send(String payload, TransportReceiver receiver) {
+  }
+}
diff --git a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java
index 00cc001..df32514 100644
--- a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java
+++ b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java
@@ -74,6 +74,7 @@
 
     @Override
     public void onFailure(ServerFailure error) {
+      assertSame(persistRequest.getRequestContext(), error.getRequestContext());
       assertEquals(expectedException, error.getExceptionType());
       if (expectedException != null) {
         assertFalse(error.getStackTraceString().length() == 0);