Revision: 8812
Author: [email protected]
Date: Fri Sep 17 12:21:10 2010
Log: Extract a RequestTransport interface and DefaultRequestTransport implementation from RequestFactory. This will allow end-users to have arbitrary control over the way RF communicates with the server.
Patch by: bobv
Review by: rjrjr
Review at http://gwt-code-reviews.appspot.com/890802

http://code.google.com/p/google-web-toolkit/source/detail?r=8812

Added:
/trunk/user/src/com/google/gwt/requestfactory/client/DefaultRequestTransport.java
 /trunk/user/src/com/google/gwt/requestfactory/shared/RequestTransport.java
Modified:
/trunk/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
 /trunk/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java

=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/requestfactory/client/DefaultRequestTransport.java Fri Sep 17 12:21:10 2010
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2010 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.requestfactory.client;
+
+import static com.google.gwt.user.client.rpc.RpcRequestBuilder.STRONG_NAME_HEADER;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.RequestException;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.requestfactory.shared.RequestEvent;
+import com.google.gwt.requestfactory.shared.RequestFactory;
+import com.google.gwt.requestfactory.shared.RequestTransport;
+import com.google.gwt.requestfactory.shared.RequestEvent.State;
+import com.google.gwt.user.client.Window.Location;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of {...@link RequestTransport} that uses a
+ * {...@link RequestBuilder}.
+ */
+public class DefaultRequestTransport implements RequestTransport {
+  /*
+   * A separate logger for wire activity, which does not get logged by the
+ * remote log handler, so we avoid infinite loops. All log messages that could + * happen every time a request is made from the server should be logged to
+   * this logger.
+   */
+ private static Logger wireLogger = Logger.getLogger("WireActivityLogger");
+  private static final String SERVER_ERROR = "Server Error";
+  private final EventBus eventBus;
+ private String requestUrl = GWT.getHostPageBaseURL() + RequestFactory.URL;
+
+  /**
+   * Construct a DefaultRequestTransport.
+   *
+ * @param eventBus the same EventBus passed into {...@link RequestFactory#init}.
+   */
+  public DefaultRequestTransport(EventBus eventBus) {
+    if (eventBus == null) {
+      throw new IllegalArgumentException("eventBus must not be null");
+    }
+    this.eventBus = eventBus;
+  }
+
+  /**
+   * Returns the current URL used by this transport.
+   */
+  public String getRequestUrl() {
+    return requestUrl;
+  }
+
+  public void send(String payload, Receiver receiver) {
+    RequestBuilder builder = createRequestBuilder();
+    configureRequestBuilder(builder);
+
+    builder.setRequestData(payload);
+    builder.setCallback(createRequestCallback(receiver));
+
+    try {
+      wireLogger.finest("Sending fire request");
+      builder.send();
+      postRequestEvent(State.SENT, null);
+    } catch (RequestException e) {
+ wireLogger.log(Level.SEVERE, SERVER_ERROR + " (" + e.getMessage() + ")",
+          e);
+    }
+  }
+
+  /**
+   * Override the default URL used by this transport.
+   */
+  public void setRequestUrl(String url) {
+    this.requestUrl = url;
+  }
+
+  /**
+   * Override to change the headers sent in the HTTP request.
+   */
+  protected void configureRequestBuilder(RequestBuilder builder) {
+ builder.setHeader("Content-Type", RequestFactory.JSON_CONTENT_TYPE_UTF8);
+    builder.setHeader("pageurl", Location.getHref());
+    builder.setHeader(STRONG_NAME_HEADER, GWT.getPermutationStrongName());
+  }
+
+  /**
+ * Constructs a RequestBuilder using the {...@link RequestBuilder#POST} method
+   * sent to the URL returned from {...@link #getRequestUrl()}.
+   */
+  protected RequestBuilder createRequestBuilder() {
+    return new RequestBuilder(RequestBuilder.POST, getRequestUrl());
+  }
+
+  /**
+   * Creates a RequestCallback that maps the HTTP response onto the
+   * {...@link Receiver} interface.
+   */
+ protected RequestCallback createRequestCallback(final Receiver receiver) {
+    return new RequestCallback() {
+
+      public void onError(Request request, Throwable exception) {
+        postRequestEvent(State.RECEIVED, null);
+        wireLogger.log(Level.SEVERE, SERVER_ERROR, exception);
+        receiver.onFailure(exception.getMessage());
+      }
+
+      public void onResponseReceived(Request request, Response response) {
+        wireLogger.finest("Response received");
+        try {
+          if (200 == response.getStatusCode()) {
+            String text = response.getText();
+            receiver.onSuccess(text);
+ } else if (Response.SC_UNAUTHORIZED == response.getStatusCode()) {
+            String message = "Need to log in";
+            wireLogger.finest(message);
+            receiver.onFailure(message);
+          } else if (response.getStatusCode() > 0) {
+            /*
+ * During the redirection for logging in, we get a response with no + * status code, but it's not an error, so we only log errors with
+             * bad status codes here.
+             */
+            String message = SERVER_ERROR + " " + response.getStatusCode()
+                + " " + response.getText();
+            wireLogger.severe(message);
+            receiver.onFailure(message);
+          }
+        } finally {
+          postRequestEvent(State.RECEIVED, response);
+        }
+      }
+    };
+  }
+
+  private void postRequestEvent(State received, Response response) {
+    eventBus.fireEvent(new RequestEvent(received, response));
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/requestfactory/shared/RequestTransport.java Fri Sep 17 12:21:10 2010
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 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.requestfactory.shared;
+
+/**
+ * Abstracts the mechanism by which a RequestFactory instance transmits its
+ * payload to the backend.
+ *
+ * @see com.google.gwt.requestfactory.client.DefaultRequestTransport
+ */
+public interface RequestTransport {
+  /**
+   * A callback interface.
+   */
+  public interface Receiver {
+    void onSuccess(String payload);
+
+    void onFailure(String message);
+  }
+
+  /**
+   * Called by the RequestFactory implementation.
+   */
+  void send(String payload, Receiver receiver);
+}
=======================================
--- /trunk/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java Thu Sep 16 08:54:56 2010 +++ /trunk/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java Fri Sep 17 12:21:10 2010
@@ -15,26 +15,20 @@
  */
 package com.google.gwt.requestfactory.client.impl;

-import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.shared.EventBus;
-import com.google.gwt.http.client.Request;
-import com.google.gwt.http.client.RequestBuilder;
-import com.google.gwt.http.client.RequestCallback;
-import com.google.gwt.http.client.RequestException;
-import com.google.gwt.http.client.Response;
+import com.google.gwt.requestfactory.client.DefaultRequestTransport;
 import com.google.gwt.requestfactory.shared.EntityProxy;
 import com.google.gwt.requestfactory.shared.EntityProxyId;
 import com.google.gwt.requestfactory.shared.ProxyRequest;
-import com.google.gwt.requestfactory.shared.RequestEvent;
-import com.google.gwt.requestfactory.shared.RequestEvent.State;
 import com.google.gwt.requestfactory.shared.RequestFactory;
 import com.google.gwt.requestfactory.shared.RequestObject;
+import com.google.gwt.requestfactory.shared.RequestTransport;
+import com.google.gwt.requestfactory.shared.ServerFailure;
 import com.google.gwt.requestfactory.shared.WriteOperation;
-import com.google.gwt.user.client.Window.Location;
+import com.google.gwt.requestfactory.shared.impl.RequestData;

 import java.util.HashMap;
 import java.util.Map;
-import java.util.logging.Level;
 import java.util.logging.Logger;

 /**
@@ -59,8 +53,9 @@
       return perSchemaMap.get(datastoreId);
     }

-    /* returns the previous futureId, if any*/
- Object put(Object datastoreId, ProxySchema<? extends ProxyImpl> schema, Object futureId) {
+    /* returns the previous futureId, if any */
+    Object put(Object datastoreId, ProxySchema<? extends ProxyImpl> schema,
+        Object futureId) {
       Map<Object, Object> perSchemaMap = internalMap.get(schema);
       if (perSchemaMap == null) {
         perSchemaMap = new HashMap<Object, Object>();
@@ -69,25 +64,19 @@
       return perSchemaMap.put(datastoreId, futureId);
     }
   }
+
   static final boolean IS_FUTURE = true;
   static final boolean NOT_FUTURE = false;

private static Logger logger = Logger.getLogger(RequestFactory.class.getName());

-  // A separate logger for wire activity, which does not get logged by the
-  // remote log handler, so we avoid infinite loops. All log messages that
- // could happen every time a request is made from the server should be logged
-  // to this logger.
- private static Logger wireLogger = Logger.getLogger("WireActivityLogger");
-
-  private static String SERVER_ERROR = "Server Error";
-
   private final Integer initialVersion = 1;
   /*
    * Keeping these maps forever is not a desirable solution because of the
* memory overhead but need these if want to provide stable {...@entityproxyid}.
    *
- * futureToDatastoreMap is currently not used, will be useful in find requests.
+   * futureToDatastoreMap is currently not used, will be useful in find
+   * requests.
    */
final Map<Object, Object> futureToDatastoreMap = new HashMap<Object, Object>();

@@ -99,6 +88,8 @@

   private EventBus eventBus;

+  private RequestTransport transport;
+
   public <R extends ProxyImpl> R create(Class<R> token,
       ProxyToTypeMap recordToTypeMap) {

@@ -114,55 +105,30 @@
     return findRequest().find(proxyId);
   }

-  public void fire(final RequestObject<?> requestObject) {
-    RequestBuilder builder = new RequestBuilder(RequestBuilder.POST,
-        GWT.getHostPageBaseURL() + RequestFactory.URL);
- builder.setHeader("Content-Type", RequestFactory.JSON_CONTENT_TYPE_UTF8);
-    builder.setHeader("pageurl", Location.getHref());
-
- builder.setRequestData(ClientRequestHelper.getRequestString(((AbstractRequest<?, ?>) requestObject).getRequestData().getRequestMap( - ((AbstractRequest<?, ?>) requestObject).deltaValueStore.toJson())));
-    builder.setCallback(new RequestCallback() {
-
-      public void onError(Request request, Throwable exception) {
-        postRequestEvent(State.RECEIVED, null);
-        wireLogger.log(Level.SEVERE, SERVER_ERROR, exception);
+  public void fire(RequestObject<?> requestObject) {
+ final AbstractRequest<?, ?> abstractRequest = (AbstractRequest<?, ?>) requestObject; + RequestData requestData = ((AbstractRequest<?, ?>) requestObject).getRequestData(); + Map<String, String> requestMap = requestData.getRequestMap(abstractRequest.deltaValueStore.toJson());
+    String payload = ClientRequestHelper.getRequestString(requestMap);
+    transport.send(payload, new RequestTransport.Receiver() {
+      public void onFailure(String message) {
+        abstractRequest.receiver.onFailure(new ServerFailure(message, null,
+            null));
       }

-      public void onResponseReceived(Request request, Response response) {
-        wireLogger.finest("Response received");
-        try {
-          if (200 == response.getStatusCode()) {
-            String text = response.getText();
- ((AbstractRequest<?, ?>) requestObject).handleResponseText(text); - } else if (Response.SC_UNAUTHORIZED == response.getStatusCode()) {
-            wireLogger.finest("Need to log in");
-          } else if (response.getStatusCode() > 0) {
- // During the redirection for logging in, we get a response with no - // status code, but it's not an error, so we only log errors with
-            // bad status codes here.
-            wireLogger.severe(SERVER_ERROR + " " + response.getStatusCode()
-                + " " + response.getText());
-          }
-        } finally {
-          postRequestEvent(State.RECEIVED, response);
-        }
+      public void onSuccess(String payload) {
+        abstractRequest.handleResponseText(payload);
       }
     });
-
-    try {
-      wireLogger.finest("Sending fire request");
-      builder.send();
-      postRequestEvent(State.SENT, null);
-    } catch (RequestException e) {
- wireLogger.log(Level.SEVERE, SERVER_ERROR + " (" + e.getMessage() + ")",
-          e);
-    }
   }

   public Class<? extends EntityProxy> getClass(EntityProxy proxy) {
     return ((ProxyImpl) proxy).getSchema().getProxyClass();
   }
+
+  public RequestTransport getRequestTransport() {
+    return transport;
+  }

   public abstract ProxySchema<?> getSchema(String token);

@@ -173,19 +139,22 @@
       // search for the datastore id for this futureId.
       Long datastoreId = (Long) futureToDatastoreMap.get(id);
       if (datastoreId == null) {
- throw new IllegalArgumentException("Cannot call find on a proxyId before persisting");
+        throw new IllegalArgumentException(
+            "Cannot call find on a proxyId before persisting");
       }
       id = datastoreId;
     }
     return ProxyImpl.getWireFormatId(id, NOT_FUTURE, proxyIdImpl.schema);
   }

-  /**
-   * @param eventBus
-   */
   public void init(EventBus eventBus) {
+    init(eventBus, new DefaultRequestTransport(eventBus));
+  }
+
+  public void init(EventBus eventBus, RequestTransport transport) {
     this.valueStore = new ValueStoreJsonImpl();
     this.eventBus = eventBus;
+    this.transport = transport;
     logger.fine("Successfully initialized RequestFactory");
   }

@@ -200,7 +169,7 @@
     }
     return schema.getProxyClass();
   }
-
+
   /**
    * TODO(amitmanjhi): remove this method, use getProxyId instead.
    */
@@ -229,7 +198,8 @@
     return schema.create(ProxyJsoImpl.create(id, -1, schema, this));
   }

- protected EntityProxyId getProxyId(String token, ProxyToTypeMap recordToTypeMap) {
+  protected EntityProxyId getProxyId(String token,
+      ProxyToTypeMap recordToTypeMap) {
     String[] bits = token.split(EntityProxyIdImpl.SEPARATOR);
     if (bits.length != 2) {
       return null;
@@ -291,8 +261,4 @@
         schema, this);
     return schema.create(newRecord, IS_FUTURE);
   }
-
-  private void postRequestEvent(State received, Response response) {
-    eventBus.fireEvent(new RequestEvent(received, response));
-  }
-}
+}
=======================================
--- /trunk/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java Wed Sep 15 03:48:29 2010 +++ /trunk/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java Fri Sep 17 12:21:10 2010
@@ -86,7 +86,13 @@
   String getToken(EntityProxy proxy);

   /**
-   * Start this request factory.
+   * Start this request factory with a
+   * {...@link com.google.gwt.requestfactory.client.DefaultRequestTransport}.
    */
   void init(EventBus eventBus);
-}
+
+  /**
+   * Start this request factory with a user-provided transport.
+   */
+  void init(EventBus eventBus, RequestTransport transport);
+}

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to