Package com.google.gwt.user.rebind.rpc

Source Code of com.google.gwt.user.rebind.rpc.ProxyCreator

/*
* 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.rebind.rpc;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPackage;
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.dev.generator.NameFactory;
import com.google.gwt.user.client.ResponseTextHandler;
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.ServiceDefTarget;
import com.google.gwt.user.client.rpc.ServiceDefTarget.NoServiceEntryPointSpecifiedException;
import com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader;
import com.google.gwt.user.client.rpc.impl.ClientSerializationStreamWriter;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

import java.io.PrintWriter;

/**
* Creates a client-side proxy for a
* {@link com.google.gwt.user.client.rpc.RemoteService RemoteService} interface
* as well as the necessary type and field serializers.
*/
class ProxyCreator {
  private static final String ENTRY_POINT_TAG = "gwt.defaultEntryPoint";
  private static final String PROXY_SUFFIX = "_Proxy";

  private static final String SERIALIZATION_STREAM_READER_INSTANTIATION = ClientSerializationStreamReader.class.getName()
      + " streamReader = new "
      + ClientSerializationStreamReader.class.getName() + "(SERIALIZER);";

  private static final String SERIALIZATION_STREAM_WRITER_INSTANTIATION = ClientSerializationStreamWriter.class.getName()
      + " streamWriter = new "
      + ClientSerializationStreamWriter.class.getName() + "(SERIALIZER);";

  /*
   * This method returns the real type name. Currently, it only affects
   * JParameterizedType since their names are not legal Java names.
   */
  private static String getJavaTypeName(JType type) {
    JParameterizedType parameterizedType = type.isParameterized();
    if (parameterizedType != null) {
      return parameterizedType.getRawType().getQualifiedSourceName();
    }

    return type.getQualifiedSourceName();
  }

  private boolean enforceTypeVersioning;

  private JClassType serviceIntf;

  public ProxyCreator(JClassType serviceIntf) {
    assert (serviceIntf.isInterface() != null);

    this.serviceIntf = serviceIntf;
  }

  /**
   * Creates the client-side proxy class.
   *
   * @throws UnableToCompleteException
   */
  public String create(TreeLogger logger, GeneratorContext context)
      throws UnableToCompleteException {
    SourceWriter srcWriter = getSourceWriter(logger, context);
    if (srcWriter == null) {
      return getProxyQualifiedName();
    }

    SerializableTypeOracleBuilder stob = new SerializableTypeOracleBuilder(
        logger, context.getTypeOracle());
    SerializableTypeOracle sto = stob.build(context.getPropertyOracle(),
        serviceIntf);

    TypeSerializerCreator tsc = new TypeSerializerCreator(logger, sto, context,
        serviceIntf);
    tsc.realize(logger);

    enforceTypeVersioning = Shared.shouldEnforceTypeVersioning(logger,
        context.getPropertyOracle());

    generateProxyFields(srcWriter, sto);

    generateServiceDefTargetImpl(srcWriter);

    generateProxyMethods(srcWriter, sto);

    srcWriter.commit(logger);

    return getProxyQualifiedName();
  }

  /*
   * Given a type emit an expression for calling the correct
   * SerializationStreamReader method which reads the corresponding
   * instance out of the stream.
   */
  protected final void generateDecodeCall(SourceWriter w, JType type) {
    w.print("streamReader.");
    w.print("read" + Shared.getCallSuffix(type) + "()");
  }

  /*
   * Given a type emit an expression for calling the correct
   * SerializationStreamWriter method which writes that type into the stream.
   */
  protected void generateEncodeCall(SourceWriter w, JParameter parameter) {
    JType paramType = parameter.getType();
    w.print("streamWriter.");
    w.print("write" + Shared.getCallSuffix(paramType));
    w.println("(" + parameter.getName() + ");");
  }

  /*
   * Calls the __ version to encode.
   */
  private void generateAsynchronousProxyMethod(SourceWriter w, JMethod method) {

    JType returnType = method.getReturnType();
    JParameter[] params = method.getParameters();

    NameFactory nameFactory = new NameFactory();

    for (int i = 0; i < params.length; ++i) {
      nameFactory.addName(params[i].getName());
    }

    w.println();
    w.print("public void " + method.getName() + "(");
    int i;
    for (i = 0; i < params.length; i++) {
      JParameter param = params[i];
      w.print((i > 0 ? ", " : "") + getJavaTypeName(param.getType()) + " "
          + param.getName());
    }

    w.println((i > 0 ? ", final " : "final ") + AsyncCallback.class.getName()
        + " callback) {");
    w.indent();
    w.println("final " + SERIALIZATION_STREAM_READER_INSTANTIATION);
    w.println("final " + SERIALIZATION_STREAM_WRITER_INSTANTIATION);
    w.println("try {");
    w.indent();
    {
      w.print("__" + method.getName() + "(streamWriter");
      for (i = 0; i < params.length; i++) {
        w.print(", " + params[i].getName());
      }
      w.println(");");
    }
    w.outdent();

    String exceptionName = nameFactory.createName("e");
    w.println("} catch (" + SerializationException.class.getName() + " "
        + exceptionName + ") {");
    w.indentln("callback.onFailure(" + exceptionName + ");");
    w.indentln("return;");
    w.println("}");

    // Generate the async response handler.
    //
    w.println(ResponseTextHandler.class.getName() + " handler = new "
        + ResponseTextHandler.class.getName() + "() {");
    w.indent();
    {
      w.println("public final void onCompletion(String encodedResponse) {");
      w.indent();
      {
        w.println("UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();");
        w.println("if (handler != null)");
        w.indent();
        {
          w.println("onCompletionAndCatch(encodedResponse, handler);");
        }
        w.outdent();
        w.println("else");
        w.indent();
        {
          w.println("onCompletionImpl(encodedResponse);");
        }
        w.outdent();
      }
      w.outdent();
      w.println("}");

      w.println("private void onCompletionAndCatch(String encodedResponse, UncaughtExceptionHandler handler) {");
      w.indent();
      {
        w.println("try {");
        w.indent();
        {
          w.println("onCompletionImpl(encodedResponse);");
        }
        w.outdent();
        w.println("} catch (Throwable e) {");
        w.indent();
        {
          w.println("handler.onUncaughtException(e);");
        }
        w.outdent();
        w.println("}");
      }
      w.outdent();
      w.println("}");

      w.println("private void onCompletionImpl(String encodedResponse) {");
      w.indent();
      {
        w.println("Object result = null;");
        w.println("Throwable caught = null;");
        w.println("try {");
        w.indent();
        {
          w.println("if (encodedResponse.startsWith(\"//OK\")) {");
          w.indent();
          {
            w.println("streamReader.prepareToRead(encodedResponse.substring(4));");
            w.print("result = ");

            JPrimitiveType primitive = returnType.isPrimitive();
            if (primitive == JPrimitiveType.VOID) {
              w.print("null");
            } else {
              if (primitive != null) {
                w.print("new ");
                w.print(getObjectWrapperName(primitive));
                w.print("(");
                generateDecodeCall(w, returnType);
                w.print(")");
              } else {
                generateDecodeCall(w, returnType);
              }
            }
            w.println(";");
          }
          w.outdent();
          w.println("} else if (encodedResponse.startsWith(\"//EX\")) {");
          w.indent();
          {
            w.println("streamReader.prepareToRead(encodedResponse.substring(4));");
            w.println("caught = (Throwable) streamReader.readObject();");
          }
          w.outdent();
          w.println("} else {");
          w.indent();
          {
            w.println("caught = new " + InvocationException.class.getName()
                + "(encodedResponse);");
          }
          w.outdent();
          w.println("}");
        }
        w.outdent();
        w.println("} catch (" + SerializationException.class.getName() + " e) {");
        w.indent();
        {
          w.println("caught = new " + IncompatibleRemoteServiceException.class.getName() + "();");
        }
        w.outdent();
        w.println("} catch (Throwable e) {");
        w.indent();
        {
          w.println("caught = e;");
        }
        w.outdent();
        w.println("}");

        w.println("if (caught == null)");
        w.indent();
        {
          w.println("callback.onSuccess(result);");
        }
        w.outdent();
        w.println("else");
        w.indent();
        {
          w.println("callback.onFailure(caught);");
        }
        w.outdent();
      }
      w.outdent();
      w.println("}");
    }
    w.outdent();
    w.println("};");

    // Make the asynchronous invocation.
    //
    w.println("if (!com.google.gwt.user.client.HTTPRequest.asyncPost(getServiceEntryPoint(), streamWriter.toString(), handler))");
    w.indentln("callback.onFailure(new "
        + InvocationException.class.getName()
        + "(\"Unable to initiate the asynchronous service invocation -- check the network connection\"));");
    w.outdent();

    w.println("}");
  }

  /**
   * Generate the code that addresses the service.
   */
  private void generateProxyEncode(SourceWriter w,
      SerializableTypeOracle serializableTypeOracle, JMethod method) {
    String methodName = method.getName();
    JParameter[] params = method.getParameters();
    w.println();
    w.print("private void __" + methodName + "("
        + ClientSerializationStreamWriter.class.getName() + " streamWriter");
    for (int i = 0; i < params.length; i++) {
      JParameter param = params[i];
      w.print(", " + getJavaTypeName(param.getType()) + " " + param.getName());
    }

    w.println(") throws " + SerializationException.class.getName() + " {");
    w.indent();

    // Make sure that we have a service def class name specified.
    //
    w.println("if (getServiceEntryPoint() == null)");
    String className = NoServiceEntryPointSpecifiedException.class.getName();
    className = className.replace('$', '.');
    w.indentln("throw new " + className + "();");

    // Generate code to describe just enough meta data for the server to locate
    // the service definition class and resolve the method overload.
    //
    w.println("streamWriter.prepareToWrite();");

    if (!shouldEnforceTypeVersioning()) {
      w.println("streamWriter.addFlags("
          + ClientSerializationStreamReader.class.getName()
          + ".SERIALIZATION_STREAM_FLAGS_NO_TYPE_VERSIONING);");
    }
    w.println("streamWriter.writeString(\""
        + serializableTypeOracle.getSerializedTypeName(method.getEnclosingType())
        + "\");");
    w.println("streamWriter.writeString(\"" + methodName + "\");");
    w.println("streamWriter.writeInt(" + params.length + ");");
    for (int i = 0; i < params.length; ++i) {
      JParameter param = params[i];
      w.println("streamWriter.writeString(\""
          + serializableTypeOracle.getSerializedTypeName(param.getType())
          + "\");");
    }

    // Encode the arguments.
    //
    for (int i = 0; i < params.length; i++) {
      JParameter param = params[i];
      generateEncodeCall(w, param);
    }

    w.outdent();
    w.println("}");
  }

  /**
   * Generate any fields required by the proxy.
   */
  private void generateProxyFields(SourceWriter srcWriter,
      SerializableTypeOracle serializableTypeOracle) {
    String typeSerializerName = serializableTypeOracle.getTypeSerializerQualifiedName(serviceIntf);
    srcWriter.println("private static final " + typeSerializerName
        + " SERIALIZER = new " + typeSerializerName + "();");
  }

  private void generateProxyMethods(SourceWriter w,
      SerializableTypeOracle serializableTypeOracle) {

    JMethod[] methods = serviceIntf.getOverridableMethods();
    for (int i = 0; i < methods.length; ++i) {
      JMethod method = methods[i];
      generateProxyEncode(w, serializableTypeOracle, method);
      generateAsynchronousProxyMethod(w, method);
    }
  }

  /**
   * Implements the ServiceDefTarget interface to allow clients to switch which
   * back-end service definition we send calls to.
   */
  private void generateServiceDefTargetImpl(SourceWriter w) {
    String serverDefName = getDefaultServiceDefName();
    if (serverDefName != null) {
      serverDefName = "\"" + serverDefName + "\"";
    } else {
      serverDefName = "null";
    }

    w.println();
    w.println("String fServiceEntryPoint = " + serverDefName + ";");
    w.println();
    w.println("public String getServiceEntryPoint() { return fServiceEntryPoint; }");
    w.println();
    w.println("public void setServiceEntryPoint(String s) { fServiceEntryPoint = s; }");
  }

  private String getAsyncIntfQualifiedName() {
    String asyncIntf = serviceIntf.getQualifiedSourceName() + "Async";
    return asyncIntf;
  }

  private String getDefaultServiceDefName() {
    String[][] metaData = serviceIntf.getMetaData(ENTRY_POINT_TAG);
    if (metaData.length == 0) {
      return null;
    }
    return serviceIntf.getMetaData(ENTRY_POINT_TAG)[0][0];
  }

  /*
   * Determine the name of the object wrapper class to instantiate based on the
   * the type of the primitive.
   */
  private String getObjectWrapperName(JPrimitiveType primitive) {
    if (primitive == JPrimitiveType.INT) {
      return "Integer";
    } else if (primitive == JPrimitiveType.CHAR) {
      return "Character";
    }

    return Shared.capitalize(primitive.getSimpleSourceName());
  }

  private String getPackageName() {
    JPackage pkg = serviceIntf.getPackage();
    if (pkg != null) {
      return pkg.getName();
    }

    return "";
  }

  private String getProxyQualifiedName() {
    String[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
        PROXY_SUFFIX);
    return name[0].length() == 0 ? name[1] : name[0] + "." + name[1];
  }

  private String getProxySimpleName() {
    String[] name = Shared.synthesizeTopLevelClassName(serviceIntf,
        PROXY_SUFFIX);
    return name[1];
  }

  private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
    PrintWriter printWriter = ctx.tryCreate(logger, getPackageName(),
        getProxySimpleName());
    if (printWriter == null) {
      return null;
    }

    ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
        getPackageName(), getProxySimpleName());

    composerFactory.addImport(GWT.class.getName());
    String className = UncaughtExceptionHandler.class.getName();
    className = className.replace('$', '.');
    composerFactory.addImport(className);

    composerFactory.addImplementedInterface(ServiceDefTarget.class.getName());
    composerFactory.addImplementedInterface(getAsyncIntfQualifiedName());

    return composerFactory.createSourceWriter(ctx, printWriter);
  }

  private boolean shouldEnforceTypeVersioning() {
    return enforceTypeVersioning;
  }
}
TOP

Related Classes of com.google.gwt.user.rebind.rpc.ProxyCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.