This patch updates the generated, client-side RemoteService proxies to implement a SerializationStreamFactory interface.  This interface provides a way to create SerializationStreamReaders and SerializationStreamWriters that are specific to a given RemoteService proxy (this is effectively what issue 460 is asking for).

In order to keep the SerializationStreamWriter returned by SerializationStreamFactory.createStreamWriter() pure, I moved the writing of the remote service interface binary name back into the generated async proxy method.

Patch by: mmendez
Review by: scottb

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1539 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/rpc/SerializationStreamFactory.java b/user/src/com/google/gwt/user/client/rpc/SerializationStreamFactory.java
new file mode 100644
index 0000000..ad39294
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/SerializationStreamFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2007 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.gwt.user.client.rpc;
+
+/**
+ * An interface for creating {@link SerializationStreamReader}s and
+ * {@link SerializationStreamWriter}s.
+ */
+public interface SerializationStreamFactory {
+
+  /**
+   * Creates a {@link SerializationStreamReader} for the encoded string.
+   * 
+   * @param encoded an encoded serialization stream
+   * @return {@link SerializationStreamReader} for the encoded string
+   * @throws SerializationException if the encoded string is not a valid
+   *           serialization stream
+   */
+  SerializationStreamReader createStreamReader(String encoded)
+      throws SerializationException;
+
+  /**
+   * Creates a {@link SerializationStreamWriter}.
+   * 
+   * @return a {@link SerializationStreamWriter}
+   */
+  SerializationStreamWriter createStreamWriter();
+}
diff --git a/user/src/com/google/gwt/user/client/rpc/SerializationStreamWriter.java b/user/src/com/google/gwt/user/client/rpc/SerializationStreamWriter.java
index cde9658..951fde3 100644
--- a/user/src/com/google/gwt/user/client/rpc/SerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/client/rpc/SerializationStreamWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 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
@@ -16,9 +16,15 @@
 package com.google.gwt.user.client.rpc;
 
 /**
- * An interface for writing values from a stream.
+ * An interface for writing values into a stream.
  */
 public interface SerializationStreamWriter {
+  /**
+   * Serializes the contents of this stream into a string.
+   * 
+   * @return a string that is the serialization of the contents of this stream
+   */
+  String toString();
 
   void writeBoolean(boolean value) throws SerializationException;
 
@@ -39,5 +45,4 @@
   void writeShort(short value) throws SerializationException;
 
   void writeString(String value) throws SerializationException;
-
 }
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java b/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java
index 4289a93..83e9c8c 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java
@@ -21,6 +21,7 @@
 import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.rpc.InvocationException;
 import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamFactory;
 import com.google.gwt.user.client.rpc.ServiceDefTarget;
 import com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter.ResponseReader;
 
@@ -30,18 +31,53 @@
  * 
  * For internal use only.
  */
-public abstract class RemoteServiceProxy implements ServiceDefTarget {
+public abstract class RemoteServiceProxy implements SerializationStreamFactory,
+    ServiceDefTarget {
+  /**
+   * Return <code>true</code> if the encoded response contains a value
+   * returned by the method invocation.
+   * 
+   * @param encodedResponse
+   * @return <code>true</code> if the encoded response contains a value
+   *         returned by the method invocation
+   */
+  static boolean isReturnValue(String encodedResponse) {
+    return encodedResponse.startsWith("//OK");
+  }
+
+  /**
+   * Return <code>true</code> if the encoded response contains a checked
+   * exception that was thrown by the method invocation.
+   * 
+   * @param encodedResponse
+   * @return <code>true</code> if the encoded response contains a checked
+   *         exception that was thrown by the method invocation
+   */
+  static boolean isThrownException(String encodedResponse) {
+    return encodedResponse.startsWith("//EX");
+  }
+
+  /**
+   * Returns a string that encodes the result of a method invocation.
+   * Effectively, this just removes any headers from the encoded response.
+   * 
+   * @param encodedResponse
+   * @return string that encodes the result of a method invocation
+   */
+  private static String getEncodedInstance(String encodedResponse) {
+    if (isReturnValue(encodedResponse) || isThrownException(encodedResponse)) {
+      return encodedResponse.substring(4);
+    }
+
+    return encodedResponse;
+  }
+
   /**
    * The module base URL as specified during construction.
    */
   private final String moduleBaseURL;
 
   /**
-   * The name of the remote service interface that we will invoke methods on.
-   */
-  private final String remoteServiceIntfName;
-
-  /**
    * URL of the
    * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService}.
    */
@@ -59,10 +95,8 @@
   private final Serializer serializer;
 
   protected RemoteServiceProxy(String moduleBaseURL, String remoteServiceURL,
-      String serializationPolicyName, String remoteServiceInfName,
-      Serializer serializer) {
+      String serializationPolicyName, Serializer serializer) {
     this.moduleBaseURL = moduleBaseURL;
-    this.remoteServiceIntfName = remoteServiceInfName;
     this.remoteServiceURL = remoteServiceURL;
     this.serializer = serializer;
     this.serializationPolicyName = serializationPolicyName;
@@ -81,8 +115,8 @@
   public ClientSerializationStreamReader createStreamReader(String encoded)
       throws SerializationException {
     ClientSerializationStreamReader clientSerializationStreamReader = new ClientSerializationStreamReader(
-        getSerializer());
-    clientSerializationStreamReader.prepareToRead(RequestCallbackAdapter.getEncodedInstance(encoded));
+        serializer);
+    clientSerializationStreamReader.prepareToRead(getEncodedInstance(encoded));
     return clientSerializationStreamReader;
   }
 
@@ -101,9 +135,8 @@
    */
   public ClientSerializationStreamWriter createStreamWriter() {
     ClientSerializationStreamWriter clientSerializationStreamWriter = new ClientSerializationStreamWriter(
-        getSerializer(), getModuleBaseURL(), getSerializationPolicyName());
+        serializer, moduleBaseURL, serializationPolicyName);
     clientSerializationStreamWriter.prepareToWrite();
-    clientSerializationStreamWriter.writeString(remoteServiceIntfName);
     return clientSerializationStreamWriter;
   }
 
@@ -141,7 +174,7 @@
     }
 
     RequestCallbackAdapter<T> responseHandler = new RequestCallbackAdapter<T>(
-        getSerializer(), callback, responseReader);
+        this, callback, responseReader);
     RequestBuilder rb = new RequestBuilder(RequestBuilder.POST,
         getServiceEntryPoint());
     try {
@@ -155,31 +188,4 @@
 
     return null;
   }
-
-  /**
-   * Returns the this proxy's module base URL.
-   * 
-   * @return this proxy's module base URL
-   */
-  protected String getModuleBaseURL() {
-    return moduleBaseURL;
-  }
-
-  /**
-   * Returns the name of the serialization policy.
-   * 
-   * @return name of the serialization policy
-   */
-  protected String getSerializationPolicyName() {
-    return serializationPolicyName;
-  }
-
-  /**
-   * Returns the {@link Serializer} instance used by this client proxy.
-   * 
-   * @return {@link Serializer} instance used by this client proxy
-   */
-  protected Serializer getSerializer() {
-    return serializer;
-  }
 }
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java b/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java
index 9b8f2c2..49eda50 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java
@@ -19,7 +19,10 @@
 import com.google.gwt.http.client.RequestCallback;
 import com.google.gwt.http.client.Response;
 import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
+import com.google.gwt.user.client.rpc.InvocationException;
 import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamFactory;
 import com.google.gwt.user.client.rpc.SerializationStreamReader;
 
 /**
@@ -128,47 +131,6 @@
   }
 
   /**
-   * Returns a string that encodes the result of a method invocation.
-   * Effectively, this just removes any headers from the encoded response.
-   * 
-   * @param encodedResponse
-   * @return string that encodes the result of a method invocation
-   */
-  static String getEncodedInstance(String encodedResponse) {
-    assert (!isInvocationException(encodedResponse));
-    return encodedResponse.substring(4);
-  }
-
-  private static boolean isInvocationException(String encodedResponse) {
-    return !isThrownException(encodedResponse)
-        && !isReturnValue(encodedResponse);
-  }
-
-  /**
-   * Return <code>true</code> if the encoded response contains a value
-   * returned by the method invocation.
-   * 
-   * @param encodedResponse
-   * @return <code>true</code> if the encoded response contains a value
-   *         returned by the method invocation
-   */
-  private static boolean isReturnValue(String encodedResponse) {
-    return encodedResponse.startsWith("//OK");
-  }
-
-  /**
-   * Return <code>true</code> if the encoded response contains a checked
-   * exception that was thrown by the method invocation.
-   * 
-   * @param encodedResponse
-   * @return <code>true</code> if the encoded response contains a checked
-   *         exception that was thrown by the method invocation
-   */
-  private static boolean isThrownException(String encodedResponse) {
-    return encodedResponse.startsWith("//EX");
-  }
-
-  /**
    * {@link AsyncCallback} to notify or success or failure.
    */
   private final AsyncCallback<T> callback;
@@ -180,18 +142,18 @@
   private final ResponseReader responseReader;
 
   /**
-   * {@link Serializer} instance used by the
-   * {@link ClientSerializationStreamReader} for serialization.
+   * {@link SerializationStreamFactory} for creating
+   * {@link SerializationStreamReader}s.
    */
-  private final Serializer serializer;
+  private final SerializationStreamFactory streamFactory;
 
-  public RequestCallbackAdapter(Serializer serializer,
+  public RequestCallbackAdapter(SerializationStreamFactory streamFactory,
       AsyncCallback<T> callback, ResponseReader responseReader) {
-    assert (serializer != null);
+    assert (streamFactory != null);
     assert (callback != null);
     assert (responseReader != null);
 
-    this.serializer = serializer;
+    this.streamFactory = streamFactory;
     this.callback = callback;
     this.responseReader = responseReader;
   }
@@ -202,25 +164,20 @@
 
   @SuppressWarnings("unchecked")
   public void onResponseReceived(Request request, Response response) {
-    final ClientSerializationStreamReader streamReader = new ClientSerializationStreamReader(
-        serializer);
     T result = null;
     Throwable caught = null;
-    String encodedResponse = response.getText();
     try {
-      if (isReturnValue(encodedResponse)) {
-        streamReader.prepareToRead(getEncodedInstance(encodedResponse));
-        result = (T) responseReader.read(streamReader);
-      } else if (isThrownException(encodedResponse)) {
-        streamReader.prepareToRead(getEncodedInstance(encodedResponse));
-        caught = (Throwable) streamReader.readObject();
+      String encodedResponse = response.getText();
+
+      if (RemoteServiceProxy.isReturnValue(encodedResponse)) {
+        result = (T) responseReader.read(streamFactory.createStreamReader(encodedResponse));
+      } else if (RemoteServiceProxy.isThrownException(encodedResponse)) {
+        caught = (Throwable) streamFactory.createStreamReader(encodedResponse).readObject();
       } else {
-        assert (isInvocationException(encodedResponse));
-        caught = new com.google.gwt.user.client.rpc.InvocationException(
-            encodedResponse);
+        caught = new InvocationException(encodedResponse);
       }
     } catch (com.google.gwt.user.client.rpc.SerializationException e) {
-      caught = new com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException();
+      caught = new IncompatibleRemoteServiceException();
     } catch (Throwable e) {
       caught = e;
     }
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
index 44df0f5..d84ab11 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -138,9 +138,7 @@
 
     generateProxyFields(srcWriter, sto, serializationPolicyStrongName);
 
-    String typeSerializerName = sto.getTypeSerializerQualifiedName(serviceIntf);
-    generateProxyContructor(srcWriter, sto, serializationPolicyStrongName,
-        typeSerializerName);
+    generateProxyContructor(srcWriter);
 
     generateProxyMethods(srcWriter, sto, syncMethToAsyncMethMap);
 
@@ -154,16 +152,13 @@
    * using the default address for the
    * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService}.
    */
-  private void generateProxyContructor(SourceWriter srcWriter,
-      SerializableTypeOracle serializableTypeOracle,
-      String serializationPolicyStrongName, String typeSerializerName) {
+  private void generateProxyContructor(SourceWriter srcWriter) {
     srcWriter.println("public " + getProxySimpleName() + "() {");
     srcWriter.indent();
     srcWriter.println("super(GWT.getModuleBaseURL(),");
     srcWriter.indent();
     srcWriter.println(getDefaultServiceDefName() + ",");
     srcWriter.println("SERIALIZATION_POLICY, ");
-    srcWriter.println("REMOTE_SERVICE_INTERFACE_NAME, ");
     srcWriter.println("SERIALIZER);");
     srcWriter.outdent();
     srcWriter.outdent();
@@ -244,7 +239,8 @@
     w.print(" ");
     String streamWriterName = nameFactory.createName("streamWriter");
     w.println(streamWriterName + " = createStreamWriter();");
-    w.println("// createStreamWriter() prepared the stream and wrote the name of RemoteService");
+    w.println("// createStreamWriter() prepared the stream");
+    w.println(streamWriterName + ".writeString(REMOTE_SERVICE_INTERFACE_NAME);");
     if (needsTryCatchBlock) {
       w.println("try {");
       w.indent();