content: /*
   * 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: Also used by RpcServlet.
       */
      public static final String MODULE_BASE_HEADER = "X-GWT-Module-Base";
  
      /**
       * Used by {@link #doFinish}.
       */
      /*
       * NB: Also used by AbstractRemoteServiceServlet.
       */
      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());
          rb.setHeader(MODULE_BASE_HEADER, GWT.getModuleBaseURL());
      }
  
      /**
       * 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) {
      }
  
      public final RpcRequestBuilder setSync(boolean sync) {
          builder.setSync(sync);
          return this;
      }
  }
  