/**
  * Checks type and its supertypes for {@link ExtraTypes} annotations.
  *
  * @param type the type to examine
  * @param addModelExtraTypes if {@code true} the contents of the {@link #extraTypes} field will be
  *     added to the returned list.
  */
 private List<EntityProxyModel> checkExtraTypes(JClassType type, boolean addModelExtraTypes)
     throws UnableToCompleteException {
   Set<EntityProxyModel> toReturn = new LinkedHashSet<EntityProxyModel>();
   if (addModelExtraTypes && extraTypes != null) {
     toReturn.addAll(extraTypes);
   }
   for (JClassType toExamine : type.getFlattenedSupertypeHierarchy()) {
     ExtraTypes proxyExtraTypes = toExamine.getAnnotation(ExtraTypes.class);
     if (proxyExtraTypes != null) {
       for (Class<? extends BaseProxy> clazz : proxyExtraTypes.value()) {
         JClassType proxy = oracle.findType(clazz.getCanonicalName());
         if (proxy == null) {
           poison(
               "Unknown class %s in @%s",
               clazz.getCanonicalName(), ExtraTypes.class.getSimpleName());
         } else {
           toReturn.add(getEntityProxyType(proxy));
         }
       }
     }
   }
   if (toReturn.isEmpty()) {
     return Collections.emptyList();
   }
   return new ArrayList<EntityProxyModel>(toReturn);
 }
Example #2
0
  private static Map<JType, JClassType> findCustomSerializers(TypeOracle oracle)
      throws NotFoundException {
    Map<JType, JClassType> serializers = new HashMap<JType, JClassType>();

    JClassType serializerInterface = oracle.findType(JSONSerializer.class.getName());
    JType[] deserializeParamTypes =
        new JType[] {
          oracle.findType(com.vaadin.client.metadata.Type.class.getName()),
          oracle.findType(JSONValue.class.getName()),
          oracle.findType(ApplicationConnection.class.getName())
        };
    String deserializeMethodName = "deserialize";
    // Just test that the method exists
    serializerInterface.getMethod(deserializeMethodName, deserializeParamTypes);

    for (JClassType serializer : serializerInterface.getSubtypes()) {
      JMethod deserializeMethod =
          serializer.findMethod(deserializeMethodName, deserializeParamTypes);
      if (deserializeMethod == null) {
        continue;
      }
      JType returnType = deserializeMethod.getReturnType();

      serializers.put(returnType, serializer);
    }
    return serializers;
  }
  /** Implement additional methods defined in {@link AbstractUiCommonModelEditorDriver} */
  @Override
  protected void writeAdditionalContent(
      TreeLogger logger, GeneratorContext context, EditorModel model, SourceWriter sw)
      throws UnableToCompleteException {
    TypeOracle typeOracle = context.getTypeOracle();
    baseModelType =
        eraseType(
            typeOracle.findType("org.ovirt.engine.ui.uicommonweb.models.Model")); // $NON-NLS-1$
    entityModelType =
        eraseType(
            typeOracle.findType(
                "org.ovirt.engine.ui.uicommonweb.models.EntityModel")); //$NON-NLS-1$
    listModelType =
        eraseType(
            typeOracle.findType("org.ovirt.engine.ui.uicommonweb.models.ListModel")); // $NON-NLS-1$
    hasCleanupType =
        eraseType(typeOracle.findType("org.ovirt.engine.ui.uicommonweb.HasCleanup")); // $NON-NLS-1$

    this.logger = logger;
    this.model = model;
    this.sw = sw;

    logger.log(Type.DEBUG, "Starting to write additional Driver code"); // $NON-NLS-1$
    writeListenerMap();
    writeEventMap();
    writeOwnerModels();
    writeCleanup();
  }
  @Override
  public String interpretElement(XMLElement elem) throws UnableToCompleteException {

    if (!uiWriter.isWidgetElement(elem)) {
      return super.interpretElement(elem);
    }

    JClassType type = uiWriter.findFieldType(elem);
    TypeOracle oracle = uiWriter.getOracle();

    MessagesWriter mw = uiWriter.getMessages();
    String name = mw.consumeMessageAttribute("ph", elem);
    if ("".equals(name)) {
      name = "widget" + (++serial);
    }

    String idHolder = uiWriter.declareDomIdHolder(null);
    idToWidgetElement.put(idHolder, elem);

    if (oracle.findType(HasHTML.class.getName()).isAssignableFrom(type)) {
      return handleHasHTMLPlaceholder(elem, name, idHolder);
    }

    if (oracle.findType(HasText.class.getName()).isAssignableFrom(type)) {
      return handleHasTextPlaceholder(elem, name, idHolder);
    }

    return handleOpaqueWidgetPlaceholder(elem, name, idHolder);
  }
Example #5
0
  // BEGIN MODIFICATION
  private FieldManager getFieldManager(
      TypeOracle oracle,
      MortalLogger logger,
      PropertyOracle propertyOracle,
      boolean useLazyWidgetBuilder)
      throws UnableToCompleteException {

    // Find ginjector
    FieldManager fieldManager;
    try {
      String ginjectorClassName =
          propertyOracle.getConfigurationProperty("gin.ginjector").getValues().get(0);

      JClassType ginjectorClass = oracle.findType(ginjectorClassName);
      if (ginjectorClass == null
          || !ginjectorClass.isAssignableTo(oracle.findType(Ginjector.class.getCanonicalName()))) {
        logger.die(
            "The configuration property 'gin.ginjector' is '%s' "
                + " which doesn't identify a type inheriting from 'Ginjector'.",
            ginjectorClassName);
      }
      fieldManager = new GinFieldManager(oracle, logger, ginjectorClass, useLazyWidgetBuilder);

    } catch (BadPropertyValueException e) {
      logger.warn(
          "The configuration property 'gin.ginjector' was not found, it is required to use "
              + "gin injection for UiBinder fields. If you don't need this consider using "
              + "UiBinder.gwt.xml instead of GinUiBinder.gwt.xml in your module.");
      fieldManager = new FieldManager(oracle, logger, useLazyWidgetBuilder);
    }

    return fieldManager;
  }
  public RequestFactoryModel(TreeLogger logger, JClassType factoryType)
      throws UnableToCompleteException {
    this.logger = logger;
    this.factoryType = factoryType;
    this.oracle = factoryType.getOracle();
    collectionInterface = oracle.findType(Collection.class.getCanonicalName());
    entityProxyInterface = oracle.findType(EntityProxy.class.getCanonicalName());
    instanceRequestInterface = oracle.findType(InstanceRequest.class.getCanonicalName());
    listInterface = oracle.findType(List.class.getCanonicalName());
    mapInterface = oracle.findType(Map.class.getCanonicalName());
    requestContextInterface = oracle.findType(RequestContext.class.getCanonicalName());
    requestFactoryInterface = oracle.findType(RequestFactory.class.getCanonicalName());
    requestInterface = oracle.findType(Request.class.getCanonicalName());
    setInterface = oracle.findType(Set.class.getCanonicalName());
    splittableType = oracle.findType(Splittable.class.getCanonicalName());
    valueProxyInterface = oracle.findType(ValueProxy.class.getCanonicalName());

    extraTypes = checkExtraTypes(factoryType, false);
    for (JMethod method : factoryType.getOverridableMethods()) {
      if (method.getEnclosingType().equals(requestFactoryInterface)) {
        // Ignore methods defined an RequestFactory itself
        continue;
      }

      if (method.getParameters().length > 0) {
        poison("Unexpected parameter on method %s", method.getName());
        continue;
      }

      JClassType contextType = method.getReturnType().isInterface();
      if (contextType == null || !requestContextInterface.isAssignableFrom(contextType)) {
        poison(
            "Unexpected return type %s on method %s is not" + " an interface assignable to %s",
            method.getReturnType().getQualifiedSourceName(),
            method.getName(),
            requestContextInterface.getSimpleSourceName());
        continue;
      }

      ContextMethod.Builder builder = new ContextMethod.Builder();
      builder.setDeclaredMethod(method);
      buildContextMethod(builder, contextType);
      contextMethods.add(builder.build());
    }

    if (poisoned) {
      die(poisonedMessage());
    }
  }
Example #7
0
 protected void generateCheckRpcTokenTypeOverride(
     SourceWriter srcWriter, TypeOracle typeOracle, SerializableTypeOracle typesSentFromBrowser) {
   JClassType rpcTokenType = typeOracle.findType(RpcToken.class.getName());
   JClassType[] rpcTokenSubtypes = rpcTokenType.getSubtypes();
   String rpcTokenImplementation = "";
   for (JClassType rpcTokenSubtype : rpcTokenSubtypes) {
     if (typesSentFromBrowser.isSerializable(rpcTokenSubtype)) {
       if (rpcTokenImplementation.length() > 0) {
         // >1 implematation of RpcToken, bail
         rpcTokenImplementation = "";
         break;
       } else {
         rpcTokenImplementation = rpcTokenSubtype.getQualifiedSourceName();
       }
     }
   }
   if (rpcTokenImplementation.length() > 0) {
     srcWriter.println("@Override");
     srcWriter.println("protected void checkRpcTokenType(RpcToken token) {");
     srcWriter.indent();
     srcWriter.println("if (!(token instanceof " + rpcTokenImplementation + ")) {");
     srcWriter.indent();
     srcWriter.println(
         "throw new RpcTokenException(\"Invalid RpcToken type: "
             + "expected '"
             + rpcTokenImplementation
             + "' but got '\" + "
             + "token.getClass() + \"'\");");
     srcWriter.outdent();
     srcWriter.println("}");
     srcWriter.outdent();
     srcWriter.println("}");
   }
 }
  public void testDashesMatchesCamels() {
    JClassType stringType = types.findType("java.lang.String");
    JClassType cssResourceType = stringType; // TODO(rjrjr) get real someday

    ImplicitCssResource css =
        new ImplicitCssResource(
            "package",
            "ClassName",
            "fieldName",
            new String[] {},
            cssResourceType,
            ".ableBaker {}",
            MortalLogger.NULL,
            Collections.<JClassType>emptySet());

    FieldWriterOfGeneratedCssResource f =
        new FieldWriterOfGeneratedCssResource(stringType, css, MortalLogger.NULL);

    assertEquals(
        stringType,
        f.getReturnType(
            new String[] {"fieldName", "able-baker"}, new MonitoredLogger(MortalLogger.NULL)));

    assertEquals(FieldWriterType.GENERATED_CSS, f.getFieldType());
  }
  @Override
  void toJS(FragmentGeneratorContext context) throws UnableToCompleteException {
    TreeLogger logger =
        context.parentLogger.branch(
            TreeLogger.DEBUG, "Writing function() wrapper for JSFunction", null);

    SourceWriter sw = context.sw;
    TypeOracle typeOracle = context.typeOracle;
    JClassType functionClass = context.returnType.isClassOrInterface();

    if (functionClass.equals(typeOracle.findType(JSFunction.class.getName()))) {
      logger.log(
          TreeLogger.ERROR,
          "You must use a subinterface of JSFunction"
              + " so that the generator can extract a method signature.",
          null);
      throw new UnableToCompleteException();
    }

    // This is to support the JSFunction having the same lifetime as the
    // JSFunction object without having to use GWT.create on every JSFunction
    // object as that would discourage anonymous classes.

    sw.print("(");
    sw.print(context.parameterName);
    //  sw.print("[email protected]::exportedFunction || (");
    sw.print(".@" + JSFunction.class.getName() + "::exportedFunction || (");
    sw.print(context.parameterName);
    //    sw.print("[email protected]::exportedFunction = ");
    sw.print(".@" + JSFunction.class.getName() + "::exportedFunction = ");
    writeFunctionForMethod(context, findExportedMethod(logger, functionClass));
    sw.print("))");
  }
  private Set<BeanResolver> getFileDeclaredTypes(TreeLogger logger, TypeOracle oralce)
      throws UnableToCompleteException {
    HashSet<BeanResolver> results = new HashSet<BeanResolver>();
    ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();

    try {
      Enumeration<URL> introspections = ctxLoader.getResources("gwittir-introspection.properties");

      while (introspections.hasMoreElements()) {
        URL propsUrl = introspections.nextElement();
        logger.log(TreeLogger.Type.INFO, "Loading: " + propsUrl.toString());

        Properties props = new Properties();
        props.load(propsUrl.openStream());

        for (Entry entry : props.entrySet()) {
          String className = entry.getKey().toString();
          String[] includedProps = entry.getValue().toString().split(",");
          JClassType type = oralce.findType(className);

          if (type == null) {
            logger.log(
                TreeLogger.Type.ERROR,
                "Unable to find type " + className + " declared in " + propsUrl);
            throw new UnableToCompleteException();
          }

          results.add(new BeanResolver(logger, type, includedProps));
        }
      }
    } catch (IOException ioe) {
      logger.log(TreeLogger.Type.WARN, "Exception looking for properties files", ioe);
    }

    return results;
  }
 private boolean hasDateTimeFormatConstructor(TypeOracle typeOracle, JClassType type) {
   JType dateTimeFormatType = typeOracle.findType(DateTimeFormat.class.getName());
   return TypeOracleUtils.hasCompatibleConstructor(type, dateTimeFormatType);
 }
Example #12
0
  /**
   * Creates the client-side proxy class.
   *
   * @throws UnableToCompleteException
   */
  public String create(TreeLogger logger, GeneratorContextExt context)
      throws UnableToCompleteException {
    TypeOracle typeOracle = context.getTypeOracle();

    JClassType serviceAsync = typeOracle.findType(serviceIntf.getQualifiedSourceName() + "Async");
    if (serviceAsync == null) {
      logger.branch(
          TreeLogger.ERROR,
          "Could not find an asynchronous version for the service interface "
              + serviceIntf.getQualifiedSourceName(),
          null);
      RemoteServiceAsyncValidator.logValidAsyncInterfaceDeclaration(logger, serviceIntf);
      throw new UnableToCompleteException();
    }

    SourceWriter srcWriter = getSourceWriter(logger, context, serviceAsync);
    if (srcWriter == null) {
      return getProxyQualifiedName();
    }

    // Make sure that the async and synchronous versions of the RemoteService
    // agree with one another
    //
    RemoteServiceAsyncValidator rsav = new RemoteServiceAsyncValidator(logger, typeOracle);
    Map<JMethod, JMethod> syncMethToAsyncMethMap = rsav.validate(logger, serviceIntf, serviceAsync);

    final PropertyOracle propertyOracle = context.getPropertyOracle();

    // Load the blacklist/whitelist
    TypeFilter blacklistTypeFilter = new BlacklistTypeFilter(logger, propertyOracle);

    // Determine the set of serializable types
    Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_STOB);

    SerializableTypeOracleBuilder typesSentFromBrowserBuilder =
        new SerializableTypeOracleBuilder(logger, propertyOracle, context);
    typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter);
    SerializableTypeOracleBuilder typesSentToBrowserBuilder =
        new SerializableTypeOracleBuilder(logger, propertyOracle, context);
    typesSentToBrowserBuilder.setTypeFilter(blacklistTypeFilter);

    addRoots(logger, typeOracle, typesSentFromBrowserBuilder, typesSentToBrowserBuilder);

    try {
      ConfigurationProperty prop =
          context
              .getPropertyOracle()
              .getConfigurationProperty(TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC);
      elideTypeNames = Boolean.parseBoolean(prop.getValues().get(0));
    } catch (BadPropertyValueException e) {
      logger.log(
          TreeLogger.ERROR,
          "Configuration property "
              + TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC
              + " is not defined. Is RemoteService.gwt.xml inherited?");
      throw new UnableToCompleteException();
    }

    // Decide what types to send in each direction.
    // Log the decisions to a string that will be written later in this method
    SerializableTypeOracle typesSentFromBrowser;
    SerializableTypeOracle typesSentToBrowser;
    String rpcLog;
    {
      StringWriter stringWriter = new StringWriter();
      PrintWriter writer = new PrintWriter(stringWriter);

      typesSentFromBrowserBuilder.setLogOutputWriter(writer);
      typesSentToBrowserBuilder.setLogOutputWriter(writer);

      writer.write("====================================\n");
      writer.write("Types potentially sent from browser:\n");
      writer.write("====================================\n\n");
      writer.flush();
      typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger);

      writer.write("===================================\n");
      writer.write("Types potentially sent from server:\n");
      writer.write("===================================\n\n");
      writer.flush();
      typesSentToBrowser = typesSentToBrowserBuilder.build(logger);

      writer.close();
      rpcLog = stringWriter.toString();
    }
    event.end();

    generateTypeHandlers(logger, context, typesSentFromBrowser, typesSentToBrowser);

    String serializationPolicyStrongName =
        writeSerializationPolicyFile(logger, context, typesSentFromBrowser, typesSentToBrowser);

    String remoteServiceInterfaceName =
        elideTypeNames
            ? TypeNameObfuscator.SERVICE_INTERFACE_ID
            : SerializationUtils.getRpcTypeName(serviceIntf);
    generateProxyFields(
        srcWriter, typesSentFromBrowser, serializationPolicyStrongName, remoteServiceInterfaceName);

    generateProxyContructor(srcWriter);

    generateProxyMethods(srcWriter, typesSentFromBrowser, typeOracle, syncMethToAsyncMethMap);

    generateStreamWriterOverride(srcWriter);

    generateCheckRpcTokenTypeOverride(srcWriter, typeOracle, typesSentFromBrowser);

    srcWriter.commit(logger);

    if (context.isProdMode() || logger.isLoggable(TreeLogger.DEBUG)) {
      // Create an artifact explaining STOB's decisions. It will be emitted by
      // RpcLogLinker
      context.commitArtifact(
          logger,
          new RpcLogArtifact(
              serviceIntf.getQualifiedSourceName(), serializationPolicyStrongName, rpcLog));
    }

    return getProxyQualifiedName();
  }
  @Override
  public String generate(TreeLogger logger, GeneratorContext context, String typeName)
      throws UnableToCompleteException {
    // make sure it is an interface
    TypeOracle oracle = context.getTypeOracle();

    propertyAccessInterface = oracle.findType(Name.getSourceNameForClass(PropertyAccess.class));
    modelKeyProviderInterface = oracle.findType(Name.getSourceNameForClass(ModelKeyProvider.class));
    valueProviderInterface = oracle.findType(Name.getSourceNameForClass(ValueProvider.class));
    labelProviderInterface = oracle.findType(Name.getSourceNameForClass(LabelProvider.class));
    JClassType toGenerate = oracle.findType(typeName).isInterface();
    if (toGenerate == null) {
      logger.log(TreeLogger.ERROR, typeName + " is not an interface type");
      throw new UnableToCompleteException();
    }
    if (!toGenerate.isAssignableTo(propertyAccessInterface)) {
      logger.log(Type.ERROR, "This isn't a PropertyAccess subtype...");
      throw new UnableToCompleteException();
    }

    // Get the name of the new type
    String packageName = toGenerate.getPackage().getName();
    String simpleSourceName = toGenerate.getName().replace('.', '_') + "Impl";
    PrintWriter pw = context.tryCreate(logger, packageName, simpleSourceName);
    if (pw == null) {
      return packageName + "." + simpleSourceName;
    }

    // start making the class, with basic imports
    ClassSourceFileComposerFactory factory =
        new ClassSourceFileComposerFactory(packageName, simpleSourceName);
    factory.addImplementedInterface(typeName);
    SourceWriter sw = factory.createSourceWriter(context, pw);

    // for each method,
    for (JMethod m : toGenerate.getOverridableMethods()) {
      TreeLogger l = logger.branch(Type.DEBUG, "Building method: " + m.getReadableDeclaration());

      // no support for params at this time
      if (m.getParameters().length != 0) {
        l.log(Type.ERROR, "Method " + m.toString() + " must not have parameters.");
        throw new UnableToCompleteException();
      }

      // ask for the types that provide the property data
      JClassType ret = m.getReturnType().isClassOrInterface();
      final AbstractCreator c;
      if (ret.isAssignableTo(valueProviderInterface)) {
        c = new ValueProviderCreator(context, l, m);
      } else if (ret.isAssignableTo(modelKeyProviderInterface)) {
        c = new ModelKeyProviderCreator(context, l, m);
      } else if (ret.isAssignableTo(labelProviderInterface)) {
        c = new LabelProviderCreator(context, l, m);
      } else {
        logger.log(Type.ERROR, "Method uses a return type that cannot be generated");
        throw new UnableToCompleteException();
      }
      c.create();
      // build the method
      // public ValueProvider<T, V> name() { return NameValueProvider.instance;
      // }
      sw.println("public %1$s %2$s() {", m.getReturnType().getQualifiedSourceName(), m.getName());
      sw.indentln("return %1$s;", c.getInstanceExpression());
      sw.println("}");
    }

    sw.commit(logger);

    return factory.getCreatedClassName();
  }
  @Override
  public String generate(TreeLogger logger, GeneratorContext context, String typeName)
      throws UnableToCompleteException {
    TypeOracle oracle = context.getTypeOracle();

    // JClassType requestQueue = oracle.findType(RequestQueue.class.getName());
    JClassType toGenerate = oracle.findType(typeName);

    if (toGenerate == null) {
      logger.log(TreeLogger.ERROR, typeName + " is not an interface type");
      throw new UnableToCompleteException();
    }

    String packageName = toGenerate.getPackage().getName();
    String simpleSourceName = toGenerate.getName().replace('.', '_') + "_Impl";
    PrintWriter pw = context.tryCreate(logger, packageName, simpleSourceName);
    if (pw == null) {
      return packageName + "." + simpleSourceName;
    }

    ClassSourceFileComposerFactory factory =
        new ClassSourceFileComposerFactory(packageName, simpleSourceName);
    factory.setSuperclass(AbstractRequestQueueImpl.class.getName());
    factory.addImplementedInterface(typeName);
    SourceWriter sw = factory.createSourceWriter(context, pw);

    // Collect async services we need to provide access to, and the rpc calls they'll make
    RequestQueueModel model =
        collectModel(logger.branch(Type.DEBUG, "Collecting service info"), context, toGenerate);

    // Build a pair of RPC interfaces for serialization
    String realRpcInterfaceName =
        buildRpcInterfaces(logger.branch(Type.DEBUG, "Writing RPC interfaces"), context, model);

    // Build the getRealService() method
    String serviceQueueAsync = ServiceQueueBaseAsync.class.getName();
    sw.println("public %1$s getRealService() {", serviceQueueAsync);
    sw.indentln(
        "return %3$s.<%1$s>create(%2$s.class);",
        serviceQueueAsync, realRpcInterfaceName, GWT.class.getName());
    sw.println("}");

    // Build the methods (and maybe types?) that call addRequest()
    for (AsyncServiceModel service : model.getServices()) {
      sw.println(
          "public %1$s %2$s() {",
          service.getAsyncServiceInterfaceName(), service.getDeclaredMethodName());
      sw.indent();

      sw.println("return new %1$s() {", service.getAsyncServiceInterfaceName());
      sw.indent();

      for (AsyncServiceMethodModel method : service.getMethods()) {
        sw.println("public void %1$s(", method.getMethodName());
        StringBuilder argList = new StringBuilder();
        StringBuilder types = new StringBuilder("new String[]{");
        for (int i = 0; i < method.getArgTypes().size(); i++) {
          if (i != 0) {
            sw.print(", ");
            argList.append(", ");
            types.append(", ");
          }
          JType arg = method.getArgTypes().get(i);

          sw.print("%1$s arg%2$d", arg.getParameterizedQualifiedSourceName(), i);
          argList.append("arg").append(i);
          types.append("\"").append(escape(SerializationUtils.getRpcTypeName(arg))).append("\"");
        }
        types.append("}");
        if (method.hasCallback()) {
          if (method.getArgTypes().size() != 0) {
            sw.print(", ");
          }
          sw.print(
              "%1$s<%2$s> callback", AsyncCallback.class.getName(), method.getReturnTypeName());
        }
        sw.println(") {");
        sw.indent();

        sw.println(
            "addRequest(\"%1$s\", \"%2$s\",\n%3$s,\n",
            escape(service.getServiceName()), escape(method.getMethodName()), types.toString());
        if (method.hasCallback()) {
          sw.indentln("callback,");
        } else {
          sw.indentln("null,");
        }
        sw.indentln("new Object[]{%1$s});", argList.toString());

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

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

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

    sw.commit(logger);

    return factory.getCreatedClassName();
  }
  private RequestQueueModel collectModel(
      TreeLogger logger, GeneratorContext context, JClassType toGenerate)
      throws UnableToCompleteException {
    RequestQueueModel.Builder rqBuilder = new RequestQueueModel.Builder();

    TypeOracle typeOracle = context.getTypeOracle();
    JClassType requestQueue = typeOracle.findType(RequestQueue.class.getName());
    JClassType asyncCallback = typeOracle.findType(AsyncCallback.class.getName());
    JClassType voidType = typeOracle.findType(Void.class.getName());
    rqBuilder.setRequestQueueInterfaceName(toGenerate.getParameterizedQualifiedSourceName());

    AsyncServiceModel.Builder serviceBuilder = new AsyncServiceModel.Builder();
    for (JMethod m : toGenerate.getMethods()) {
      TreeLogger serviceLogger =
          logger.branch(Type.DEBUG, "Reading async service " + m.getReadableDeclaration());

      // Skip those defined at RequestQueue
      if (m.getEnclosingType().equals(requestQueue)) {
        continue;
      }
      JClassType returnType = m.getReturnType().isClassOrInterface();
      if (returnType == null) {
        serviceLogger.log(Type.ERROR, "Unexpected method return type " + returnType);
        throw new UnableToCompleteException();
      }

      serviceBuilder.setAsyncServiceInterfaceName(returnType.getParameterizedQualifiedSourceName());
      serviceBuilder.setDeclaredMethodName(m.getName());

      Service serviceAnnotation = m.getAnnotation(Service.class);
      if (serviceAnnotation == null) {
        serviceLogger.log(Type.ERROR, "Missing @Service annotation");
        throw new UnableToCompleteException();
      }
      serviceBuilder.setService(serviceAnnotation.value().getName());

      AsyncServiceMethodModel.Builder methodBuilder = new AsyncServiceMethodModel.Builder();
      for (JMethod asyncMethod : m.getReturnType().isClassOrInterface().getMethods()) {
        TreeLogger methodLogger =
            serviceLogger.branch(
                Type.DEBUG, "Reading service method " + asyncMethod.getReadableDeclaration());

        List<JType> types = new ArrayList<JType>();
        methodBuilder.setReturnTypeName(voidType.getParameterizedQualifiedSourceName());
        boolean asyncFound = false;
        for (JType param : asyncMethod.getParameterTypes()) {
          if (asyncFound) {
            methodLogger.log(
                Type.WARN, "Already passed an AsyncCallback param - is that what you meant?");
          }
          if (param.isClassOrInterface() != null
              && param.isClassOrInterface().isAssignableTo(asyncCallback)) {
            JClassType boxedReturnType =
                ModelUtils.findParameterizationOf(asyncCallback, param.isClassOrInterface())[0];
            methodBuilder
                .setHasCallback(true)
                .setReturnTypeName(boxedReturnType.getParameterizedQualifiedSourceName());
            asyncFound = true;
            continue; // should be last, check for this...
          }
          types.add(param);
        }
        Set<JClassType> throwables = new HashSet<JClassType>();
        Throws t = asyncMethod.getAnnotation(Throws.class);
        if (t != null) {
          for (Class<? extends Throwable> throwable : t.value()) {
            throwables.add(typeOracle.findType(throwable.getName()));
          }
        }

        methodBuilder
            .setMethodName(asyncMethod.getName())
            .setArgTypes(types)
            .setThrowables(throwables);

        serviceBuilder.addMethod(methodBuilder.build());
      }
      rqBuilder.addService(serviceBuilder.build());
    }

    return rqBuilder.build();
  }