Author: [email protected] Date: Tue Mar 10 09:06:00 2009 New Revision: 4969 Added: changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/RpcRequestBuilder.java (contents, props changed) Modified: changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/ServiceDefTarget.java changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
Log: Add the RpcRequestBuilder type to clearly enumerate the API requirements that RemoteServiceProxy has and to allow for arbitrary configuration of the HTTP request. Added: changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/RpcRequestBuilder.java ============================================================================== --- (empty file) +++ changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/RpcRequestBuilder.java Tue Mar 10 09:06:00 2009 @@ -0,0 +1,212 @@ +/* + * Copyright 2009 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; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.http.client.RequestBuilder; +import com.google.gwt.http.client.RequestCallback; + +/** + * This class encapsulates the logic necessary to configure a RequestBuilder for + * use with an RPC proxy object. Users who wish to alter the specifics of the + * HTTP requests issued by RPC proxy objects may override the protected + * <code>doXyz</code> methods and pass an instance of the subclass to + * {...@link ServiceDefTarget#setRpcRequestBuilder}. + */ +public class RpcRequestBuilder { + /** + * Used by {...@link #doSetContentType}. + */ + public static final String CONTENT_TYPE_HEADER = "Content-Type"; + + /** + * Used by {...@link #doFinish}. + */ + /* + * NB: Keep in sync with RemoteServiceServlet. + */ + public static final String STRONG_NAME_HEADER = "X-GWT-Permutation"; + + /** + * Not exposed directly to the subclass. + */ + private RequestBuilder builder; + + /** + * Initialize the RpcRequestBuilder. This method must be called before any of + * the other methods in this class may be called. Calling <code>create</code> + * before calling {...@link #finish()} will reset the state of the + * RpcRequestBuilder. + * <p> + * This method delegates to {...@link #doCreate} to instantiate the + * RequestBuilder. + * + * @param serviceEntryPoint The URL entry point + * @return <code>this</code> + * @see ServiceDefTarget#setServiceEntryPoint(String) + */ + public final RpcRequestBuilder create(String serviceEntryPoint) { + builder = doCreate(serviceEntryPoint); + assert builder != null : "doCreate failed to return a RequestBuilder"; + return this; + } + + /** + * This method must be called to return the RequestBuilder that the RPC + * request will be made with. + * <p> + * This method will call {...@link #doFinish} before returning the current + * RequestBuilder. + */ + public final RequestBuilder finish() { + try { + assert builder != null : "Call create() first"; + doFinish(builder); + return builder; + } finally { + builder = null; + } + } + + /** + * Sets the RequestCallback to be used by the RequestBuilder. Delegates to + * {...@link #doSetCallback}. + * + * @param callback the RequestCallback to be used by the RequestBuilder + * @return <code>this</code> + */ + public final RpcRequestBuilder setCallback(RequestCallback callback) { + assert builder != null : "Call create() first"; + doSetCallback(builder, callback); + return this; + } + + /** + * Sets the MIME content type to be used by the RequestBuilder. Delegates to + * {...@link #doSetContentType}. + * + * @param contentType the MIME content type to be used in the request + * @return <code>this</code> + */ + public final RpcRequestBuilder setContentType(String contentType) { + assert builder != null : "Call create() first"; + doSetContentType(builder, contentType); + return this; + } + + /** + * Sets the request data to be sent in the request. Delegates to + * {...@link #doSetRequestData}. + * + * @param data the data to send + * @return <code>this</code> + */ + public final RpcRequestBuilder setRequestData(String data) { + assert builder != null : "Call create() first"; + doSetRequestData(builder, data); + return this; + } + + /** + * Sets the request id of the request. Delegates to {...@link #doSetRequestId}. + * + * @param id the issue number of the request + * @return <code>this</code> + */ + public final RpcRequestBuilder setRequestId(int id) { + assert builder != null : "Call create() first"; + doSetRequestId(builder, id); + return this; + } + + /** + * Called by {...@link #create} to instantiate the RequestBuilder object. + * <p> + * The default implementation creates a <code>POST</code> RequestBuilder with + * the given entry point. + * + * @param serviceEntryPoint the URL to which the request should be issued + * @return the RequestBuilder that should be ultimately passed to the + * RpcRequestBuilder's caller. + */ + protected RequestBuilder doCreate(String serviceEntryPoint) { + return new RequestBuilder(RequestBuilder.POST, serviceEntryPoint); + } + + /** + * Called by {...@link #finish()} prior to returning the RequestBuilder to the + * caller. + * <p> + * The default implementation sets the {...@value #STRONG_NAME_HEADER} header to + * the value returned by {...@link GWT#getPermutationStrongName()}. + * + * @param rb The RequestBuilder that is currently being configured + */ + protected void doFinish(RequestBuilder rb) { + rb.setHeader(STRONG_NAME_HEADER, GWT.getPermutationStrongName()); + } + + /** + * Called by {...@link #setCallback}. + * <p> + * The default implementation calls + * {...@link RequestBuilder#setCallback(RequestCallback)}. + * + * @param rb the RequestBuilder that is currently being configured + * @param callback the user-provided callback + */ + protected void doSetCallback(RequestBuilder rb, RequestCallback callback) { + rb.setCallback(callback); + } + + /** + * Called by {...@link #setContentType}. + * <p> + * The default implementation sets the {...@value #CONTENT_TYPE_HEADER} header to + * the value specified by <code>contentType</code> by calling + * {...@link RequestBuilder#setHeader(String, String)}. + * + * @param rb the RequestBuilder that is currently being configured + * @param contentType the desired MIME type of the request's contents + */ + protected void doSetContentType(RequestBuilder rb, String contentType) { + rb.setHeader(CONTENT_TYPE_HEADER, contentType); + } + + /** + * Called by {...@link #setRequestData}. + * <p> + * The default implementation invokes + * {...@link RequestBuilder#setRequestData(String)}. + * + * @param rb the RequestBuilder that is currently being configured + * @param data the data to send + */ + protected void doSetRequestData(RequestBuilder rb, String data) { + rb.setRequestData(data); + } + + /** + * Called by {...@link #setRequestId}. + * <p> + * The default implementation is a no-op. + * + * @param rb the RequestBuilder that is currently being configured + * @param id the request's issue id + */ + protected void doSetRequestId(RequestBuilder rb, int id) { + } +} Modified: changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/ServiceDefTarget.java ============================================================================== --- changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/ServiceDefTarget.java (original) +++ changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/ServiceDefTarget.java Tue Mar 10 09:06:00 2009 @@ -43,6 +43,13 @@ String getServiceEntryPoint(); /** + * Sets the RpcRequestBuilder that should be used by the service + * implementation. This method can be called if customized request behavior is + * desired. + */ + void setRpcRequestBuilder(RpcRequestBuilder builder); + + /** * Sets the URL of a service implementation. * * @param address a URL that designates the service implementation to call Modified: changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java ============================================================================== --- changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java (original) +++ changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java Tue Mar 10 09:06:00 2009 @@ -15,13 +15,13 @@ */ package com.google.gwt.user.client.rpc.impl; -import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestException; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.InvocationException; +import com.google.gwt.user.client.rpc.RpcRequestBuilder; import com.google.gwt.user.client.rpc.SerializationException; import com.google.gwt.user.client.rpc.SerializationStreamFactory; import com.google.gwt.user.client.rpc.ServiceDefTarget; @@ -37,9 +37,9 @@ ServiceDefTarget { /** - * NB: Keep in sync with RemoteServiceServlet. + * The content type to be used in HTTP requests. */ - private static final String STRONG_NAME_HEADER = "X-GWT-Permutation"; + private static final String RPC_CONTENT_TYPE = "text/x-gwt-rpc; charset=utf-8"; /** * A global id to track any given request. @@ -56,9 +56,6 @@ /** * Indicates if RPC statistics should be gathered. */ - /** - * Indicates if RPC statistics should be gathered. - */ public static native boolean isStatsAvailable() /*-{ return !!$stats; }-*/; @@ -71,7 +68,8 @@ return $stats(data); }-*/; - public static native JavaScriptObject timeStat(String method, int count, String eventType) /*-{ + public static native JavaScriptObject timeStat(String method, int count, + String eventType) /*-{ return { moduleName: @com.google.gwt.core.client.GWT::getModuleName()(), subSystem: 'rpc', @@ -86,17 +84,21 @@ return requestId++; } + /** + * @deprecated Use {...@link RpcRequestBuilder} instead. + */ + @Deprecated protected static int getRequestId() { return requestId; } /** - * Return <code>true</code> if the encoded response contains a value - * returned by the method invocation. + * 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 + * @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"); @@ -135,11 +137,13 @@ private final String moduleBaseURL; /** - * URL of the - * {...@link com.google.gwt.user.client.rpc.RemoteService RemoteService}. + * URL of the {...@link com.google.gwt.user.client.rpc.RemoteService + * RemoteService}. */ private String remoteServiceURL; + private RpcRequestBuilder rpcRequestBuilder; + /** * The name of the serialization policy file specified during construction. */ @@ -169,13 +173,12 @@ } /** - * Returns a - * {...@link com.google.gwt.user.client.rpc.SerializationStreamReader SerializationStreamReader} - * that is ready for reading. + * Returns a {...@link com.google.gwt.user.client.rpc.SerializationStreamReader + * SerializationStreamReader} that is ready for reading. * * @param encoded string that encodes the response of an RPC request - * @return {...@link com.google.gwt.user.client.rpc.SerializationStreamReader SerializationStreamReader} - * that is ready for reading + * @return {...@link com.google.gwt.user.client.rpc.SerializationStreamReader + * SerializationStreamReader} that is ready for reading * @throws SerializationException */ public ClientSerializationStreamReader createStreamReader(String encoded) @@ -187,14 +190,14 @@ } /** - * Returns a - * {...@link com.google.gwt.user.client.rpc.SerializationStreamWriter SerializationStreamWriter} - * that has had {...@link ClientSerializationStreamWriter#prepareToWrite()} - * called on it and it has already had had the name of the remote service - * interface written as well. + * Returns a {...@link com.google.gwt.user.client.rpc.SerializationStreamWriter + * SerializationStreamWriter} that has had + * {...@link ClientSerializationStreamWriter#prepareToWrite()} called on it and + * it has already had had the name of the remote service interface written as + * well. * - * @return {...@link com.google.gwt.user.client.rpc.SerializationStreamWriter SerializationStreamWriter} - * that has had + * @return {...@link com.google.gwt.user.client.rpc.SerializationStreamWriter + * SerializationStreamWriter} that has had * {...@link ClientSerializationStreamWriter#prepareToWrite()} called on * it and it has already had had the name of the remote service * interface written as well @@ -213,6 +216,11 @@ return remoteServiceURL; } + public void setRpcRequestBuilder(RpcRequestBuilder builder) { + assert builder != null : "builder was null"; + this.rpcRequestBuilder = builder; + } + /** * @see ServiceDefTarget#setServiceEntryPoint(String) */ @@ -221,7 +229,8 @@ } /** - * Performs a remote service method invocation. + * Performs a remote service method invocation. This method is called by + * generated proxy classes. * * @param <T> return type for the AsyncCallback * @param responseReader instance used to read the return value of the @@ -249,7 +258,7 @@ } finally { if (RemoteServiceProxy.isStatsAvailable() && RemoteServiceProxy.stats(RemoteServiceProxy.bytesStat(methodName, - invocationCount, requestData.length(), "requestSent"))) { + invocationCount, requestData.length(), "requestSent"))) { } } return null; @@ -303,13 +312,19 @@ RequestCallbackAdapter<T> responseHandler = new RequestCallbackAdapter<T>( this, methodName, invocationCount, callback, responseReader); - RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, - getServiceEntryPoint()); + ensureRpcRequestBuilder(); - rb.setHeader("Content-Type", "text/x-gwt-rpc; charset=utf-8"); - rb.setHeader(STRONG_NAME_HEADER, GWT.getPermutationStrongName()); - rb.setCallback(responseHandler); - rb.setRequestData(requestData); - return rb; + rpcRequestBuilder.create(getServiceEntryPoint()); + rpcRequestBuilder.setCallback(responseHandler); + rpcRequestBuilder.setContentType(RPC_CONTENT_TYPE); + rpcRequestBuilder.setRequestData(requestData); + rpcRequestBuilder.setRequestId(invocationCount); + return rpcRequestBuilder.finish(); + } + + private void ensureRpcRequestBuilder() { + if (rpcRequestBuilder == null) { + rpcRequestBuilder = new RpcRequestBuilder(); + } } } Modified: changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java ============================================================================== --- changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java (original) +++ changes/bobv/rpc_request_builder/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java Tue Mar 10 09:06:00 2009 @@ -41,9 +41,12 @@ SerializationPolicyProvider { /** + * Used by {...@link #getPermutationStrongName()}. + */ + /* * NB: Keep in sync with RemoteServiceProxy. */ - private static final String STRONG_NAME_HEADER = "X-GWT-Permutation"; + protected static final String STRONG_NAME_HEADER = "X-GWT-Permutation"; private final ThreadLocal<HttpServletRequest> perThreadRequest = new ThreadLocal<HttpServletRequest>(); --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---
