@Override
  protected void doAddFieldsAndRequirements(
      TreeLogger logger,
      GeneratorContext generatorContext,
      FieldsImpl fields,
      ClientBundleRequirements requirements)
      throws UnableToCompleteException {
    JType booleanType;
    JType stringType;
    try {
      booleanType = generatorContext.getTypeOracle().parse("boolean");
      stringType = generatorContext.getTypeOracle().parse("java.lang.String");
    } catch (TypeOracleException e) {
      logger.log(TreeLogger.ERROR, "Expected type not in type oracle", e);
      throw new UnableToCompleteException();
    }

    // GWT.getModuleBaseURL().startsWith("https")
    String isHttpsIdent =
        fields.define(
            booleanType, "isHttps", "GWT.getModuleBaseURL().startsWith(\"https\")", true, true);
    resourceContext.setIsHttpsIdent(isHttpsIdent);

    // CHECKSTYLE_OFF
    // "mhtml:" + GWT.getModuleBaseURL() + "partialPath!cid:"
    // CHECKSTYLE_ON
    bundleBaseIdent = fields.define(stringType, "bundleBase", null, true, true);
    resourceContext.setBundleBaseIdent(bundleBaseIdent);
  }
  private void generateClass(TreeLogger logger, GeneratorContext context) {

    // get print writer that receives the source code
    PrintWriter printWriter = null;
    printWriter = context.tryCreate(logger, packageName, className);
    // print writer if null, source code has ALREADY been generated, return
    if (printWriter == null) {
      return;
    }

    // init composer, set class properties, create source writer
    ClassSourceFileComposerFactory composer = null;
    composer = new ClassSourceFileComposerFactory(packageName, className);
    composer.addImplementedInterface("org.pentaho.ui.xul.gwt.binding.TypeController");
    composer.addImport("org.pentaho.ui.xul.gwt.binding.*");
    composer.addImport("java.util.Map");
    composer.addImport("java.util.HashMap");
    composer.addImport("org.pentaho.ui.xul.XulException");

    SourceWriter sourceWriter = null;
    sourceWriter = composer.createSourceWriter(context, printWriter);

    // generator constructor source code
    generateConstructor(sourceWriter);

    writeMethods(sourceWriter);

    // close generated class
    sourceWriter.outdent();
    sourceWriter.println("}");

    // commit generated class
    context.commit(logger, printWriter);
  }
Exemple #3
0
  /**
   * Erases the {@link MetaClassFactory} cache, then populates it with types discovered via GWT's
   * TypeOracle. The reason for the initial flush of the MetaClassFactory is to support hot redeploy
   * in Dev Mode. The reason for doing this operation at all is so that the overridden class
   * definitions (super-source classes) are used in preference to the Java reflection based class
   * definitions.
   *
   * @param context The GeneratorContext supplied by the GWT compiler. Not null.
   * @param logger The TreeLogger supplied by the GWT compiler. Not null.
   */
  public static void populateMetaClassFactoryFromTypeOracle(
      final GeneratorContext context, final TreeLogger logger) {

    // if we're in production mode -- it means we're compiling, and we do not need to accommodate
    // dynamically
    // changing classes. Therefore, do a NOOP after the first successful call.
    if (typeOraclePopulated && (context.equals(populatedFrom.get()) || EnvUtil.isProdMode())) {
      return;
    }

    final TypeOracle typeOracle = context.getTypeOracle();
    MetaClassFactory.emptyCache();
    if (typeOracle != null) {
      final Set<String> translatable =
          new HashSet<String>(RebindUtils.findTranslatablePackages(context));
      translatable.remove("java.lang");
      translatable.remove("java.lang.annotation");

      for (final JClassType type : typeOracle.getTypes()) {
        if (!translatable.contains(type.getPackage().getName())) {
          logger.log(
              com.google.gwt.core.ext.TreeLogger.Type.DEBUG,
              "Skipping non-translatable " + type.getQualifiedSourceName());
          continue;
        }

        if (type.isAnnotation() != null
            || type.getQualifiedSourceName().equals("java.lang.annotation.Annotation")) {
          logger.log(
              com.google.gwt.core.ext.TreeLogger.Type.DEBUG,
              "Caching annotation type " + type.getQualifiedSourceName());

          if (!MetaClassFactory.canLoadClass(type.getQualifiedBinaryName())) {
            throw new RuntimeException(
                "a new annotation has been introduced ("
                    + type.getQualifiedSourceName()
                    + "); "
                    + "you cannot currently introduce new annotations in devmode. Please restart.");
          }

          MetaClassFactory.pushCache(
              JavaReflectionClass.newUncachedInstance(
                  MetaClassFactory.loadClass(type.getQualifiedBinaryName())));
        } else {
          logger.log(
              com.google.gwt.core.ext.TreeLogger.Type.DEBUG,
              "Caching translatable type " + type.getQualifiedSourceName());
          MetaClassFactory.pushCache(GWTClass.newInstance(typeOracle, type));
        }
      }
    }
    typeOraclePopulated = true;
    populatedFrom = new SoftReference<GeneratorContext>(context);
  }
 public PrintWriter getPrintWrite(String name) {
   PrintWriter writer = generatorContext.tryCreate(logger, packageName, name);
   if (writer != null) {
     writers.add(writer);
   }
   return writer;
 }
  @Override
  public String generate(TreeLogger logger, GeneratorContext context, String typeName)
      throws UnableToCompleteException {

    this.logger = logger;
    typeOracle = context.getTypeOracle();

    try {

      // find XulEventSource implementors
      implementingTypes = new ArrayList<JClassType>();
      JClassType eventSourceType = typeOracle.getType("org.pentaho.ui.xul.XulEventSource");

      for (JClassType type : typeOracle.getTypes()) {
        if (type.isAssignableTo(eventSourceType)) {
          implementingTypes.add(type);
        }
      }

      // get classType and save instance variables
      JClassType classType = typeOracle.getType(typeName);
      packageName = classType.getPackage().getName();
      className = classType.getSimpleSourceName() + "Impl";
      // Generate class source code
      generateClass(logger, context);

    } catch (Exception e) {
      // record to logger that Map generation threw an exception
      logger.log(TreeLogger.ERROR, "Error generating BindingContext!!!", e);
    }

    // return the fully qualifed name of the class generated
    return packageName + "." + className;
  }
  /** 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();
  }
  /**
   * @param logger
   * @param context
   * @param baseIntf
   */
  public DeviceAdaptiveProxyCreator(
      TreeLogger logger, GeneratorContext context, JClassType baseIntf) {
    super(logger, context, baseIntf, false);

    deviceAdaptiveControllerClass =
        context.getTypeOracle().findType(DeviceAdaptiveController.class.getCanonicalName());
    deviceAdaptiveClass = context.getTypeOracle().findType(DeviceAdaptive.class.getCanonicalName());
    hasHandlersClass = context.getTypeOracle().findType(HasHandlers.class.getCanonicalName());

    initializeTemplateParser();
    view = templateParser.getTemplateView(template, baseIntf.getQualifiedSourceName(), device);
    initializeController(view);
    viewFactoryCreator =
        new DeviceAdaptiveViewFactoryCreator(
            context, logger, view, getDeviceFeatures(), controllerName, getModule());
    viewClassName = viewFactoryCreator.create();
  }
  @Ignore("can only be ran once I make the code changes to mock out the composer factory")
  @Test
  public void generate_shouldNotAttemptToSetupTheLoggerOnTheSourceWriter()
      throws UnableToCompleteException {
    when(context.tryCreate(logger, packageName, className)).thenReturn(null);

    assertBundleClass(runGenerator());

    verifyBundleInterfaceWasSetOnTheComposer();
    verifyZeroInteractions(sourceWriter);
  }
  @Override
  public String generate(TreeLogger logger, GeneratorContext genCtx, String fqInterfaceName)
      throws UnableToCompleteException {
    TypeOracle oracle = genCtx.getTypeOracle();
    ResourceOracle resourceOracle = genCtx.getResourcesOracle();

    JClassType interfaceType;
    try {
      interfaceType = oracle.getType(fqInterfaceName);
    } catch (NotFoundException e) {
      throw new RuntimeException(e);
    }

    DesignTimeUtils designTime;
    if (DesignTimeUtilsImpl.isDesignTime(fqInterfaceName)) {
      designTime = new DesignTimeUtilsImpl();
    } else {
      designTime = DesignTimeUtilsStub.EMPTY;
    }

    String implName = interfaceType.getName().replace('.', '_') + "Impl";
    implName = designTime.getImplName(implName);

    String packageName = interfaceType.getPackage().getName();
    PrintWriterManager writers = new PrintWriterManager(genCtx, logger, packageName);
    PrintWriter printWriter = writers.tryToMakePrintWriterFor(implName);

    if (printWriter != null) {
      generateOnce(
          interfaceType,
          implName,
          printWriter,
          logger,
          oracle,
          resourceOracle,
          genCtx.getPropertyOracle(),
          writers,
          designTime);
    }
    return packageName + "." + implName;
  }
 protected static boolean isCallbackInjected(
     TreeLogger logger, String packageName, String simpleSourceName, GeneratorContext context) {
   try {
     JClassType type =
         context
             .getTypeOracle()
             .findType(packageName + "." + InjectionUtils.generatedCallbackName(simpleSourceName));
     return type != null;
   } catch (Exception e) {
     return false;
   }
 }
  @Ignore("can only be ran once I make the code changes to mock out the composer factory")
  @Test
  public void generate_shouldSetTheLoggerOnTheSourceWriter() throws Exception {
    StubPrintWriter contextWriter = new StubPrintWriter();

    when(context.tryCreate(logger, packageName, className)).thenReturn(contextWriter);
    when(composerFactory.createSourceWriter(context, contextWriter)).thenReturn(sourceWriter);

    assertBundleClass(runGenerator());

    verifyBundleInterfaceWasSetOnTheComposer();
    verify(sourceWriter).commit(logger);
  }
Exemple #12
0
  @Override
  public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String s)
      throws UnableToCompleteException {
    GinjectorGenerator ginjectorGenerator = new GinjectorGenerator();

    JClassType clazz = generatorContext.getTypeOracle().findType(s);
    GinExtension[] ginExtensions = null;
    if (clazz.isAnnotationPresent(GinExtensions.class)) {
      ginExtensions = clazz.getAnnotation(GinExtensions.class).value();
    }
    GeneratorContextWrapper gcw = new GeneratorContextWrapper(generatorContext, ginExtensions);

    return ginjectorGenerator.generate(treeLogger, gcw, s);
  }
  /**
   * Generate an implementation for the given type.
   *
   * @param logger error logger
   * @param context generator context
   * @param typeName target type name
   * @return generated class name
   * @throws UnableToCompleteException
   */
  @Override
  public final String generate(TreeLogger logger, GeneratorContext context, String typeName)
      throws UnableToCompleteException {
    assert CURRENCY_LIST.equals(typeName);
    TypeOracle typeOracle = context.getTypeOracle();

    PropertyOracle propertyOracle = context.getPropertyOracle();
    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, propertyOracle, context);
    GwtLocale locale = localeUtils.getCompileLocale();
    Set<GwtLocale> runtimeLocales = localeUtils.getRuntimeLocales();

    JClassType targetClass;
    try {
      targetClass = typeOracle.getType(typeName);
    } catch (NotFoundException e) {
      logger.log(TreeLogger.ERROR, "No such type", e);
      throw new UnableToCompleteException();
    }
    if (runtimeLocales.isEmpty()) {
      return generateLocaleTree(logger, context, targetClass, locale);
    }
    CachedGeneratorContext cachedContext = new CachedGeneratorContext(context);
    return generateRuntimeSelection(logger, cachedContext, targetClass, locale, runtimeLocales);
  }
  public static boolean ensureProviderClass(
      TreeLogger logger,
      String packageName,
      String simpleName0,
      String canonical,
      String qualifiedSourceName,
      GeneratorContext ctx) {
    String simpleName = SourceUtil.toSourceName(simpleName0);
    String generatedName = InjectionUtils.generatedProviderName(simpleName);
    String cleanedCanonical = SourceUtil.toSourceName(canonical);
    logger.log(Type.DEBUG, "Creating provider for " + packageName + "." + generatedName);

    PrintWriter printWriter = ctx.tryCreate(logger, packageName, generatedName);
    if (printWriter == null) {
      logger.log(Type.TRACE, "Already generated " + generatedName);
      return false;
    }
    logger.log(
        Type.TRACE, "Newly Generating provider " + generatedName + " <- " + qualifiedSourceName);

    ClassSourceFileComposerFactory composer =
        new ClassSourceFileComposerFactory(packageName, generatedName);
    composer.setSuperclass(SingletonInitializer.class.getName() + "<" + simpleName0 + ">");
    composer.addImport(cleanedCanonical);
    composer.addImport(GWT.class.getName());
    composer.addImport(SingletonProvider.class.getName());

    SourceWriter sw = composer.createSourceWriter(ctx, printWriter);

    sw.println("@Override");
    sw.println("public " + simpleName + " initialValue(){");
    sw.indent();

    sw.print("return GWT.<" + cleanedCanonical + ">create(");
    sw.print(SourceUtil.toSourceName(qualifiedSourceName) + ".class");
    sw.println(");");

    sw.outdent();
    sw.println("}");
    sw.println();
    // now, print a static final provider instance
    sw.print("public static final SingletonProvider<");
    sw.print(simpleName0 + "> ");
    sw.print("theProvider = ");
    sw.println("new " + generatedName + "();");
    sw.commit(logger);
    return true;
  }
 /**
  * Generate the implementation for a single locale, overriding from its parent only data that has
  * changed in this locale.
  *
  * @param logger
  * @param context
  * @param targetClass
  * @param locale
  * @param superClassName
  * @param currencies the set of currencies defined in this locale
  * @param allCurrencyData map of currency code -> unparsed CurrencyInfo for that code
  * @param defCurrencyCode default currency code for this locale
  * @return fully-qualified class name generated
  */
 private String generateOneLocale(
     TreeLogger logger,
     GeneratorContext context,
     JClassType targetClass,
     GwtLocale locale,
     String superClassName,
     String[] currencies,
     Map<String, CurrencyInfo> allCurrencyData,
     String defCurrencyCode) {
   String packageName = targetClass.getPackage().getName();
   String className = targetClass.getName().replace('.', '_') + "_" + locale.getAsString();
   PrintWriter pw = context.tryCreate(logger, packageName, className);
   if (pw != null) {
     ClassSourceFileComposerFactory factory =
         new ClassSourceFileComposerFactory(packageName, className);
     factory.setSuperclass(superClassName);
     factory.addImport(CURRENCY_DATA);
     factory.addImport(JAVASCRIPTOBJECT);
     factory.addImport(HASHMAP);
     SourceWriter writer = factory.createSourceWriter(context, pw);
     if (defCurrencyCode != null) {
       CurrencyInfo currencyInfo = allCurrencyData.get(defCurrencyCode);
       if (currencyInfo == null) {
         // Synthesize a null info if the specified default wasn't found.
         currencyInfo = new CurrencyInfo(defCurrencyCode, null, null);
         allCurrencyData.put(defCurrencyCode, currencyInfo);
       }
       writer.println();
       writer.println("@Override");
       writer.println("protected CurrencyData getDefaultJava() {");
       writer.println("  return " + currencyInfo.getJava() + ";");
       writer.println("}");
       writer.println();
       writer.println("@Override");
       writer.println("protected native CurrencyData getDefaultNative() /*-{");
       writer.println("  return " + currencyInfo.getJson() + ";");
       writer.println("}-*/;");
     }
     if (currencies.length > 0) {
       writeCurrencyMethodJava(writer, currencies, allCurrencyData);
       writeCurrencyMethodNative(writer, currencies, allCurrencyData);
       writeNamesMethodJava(writer, currencies, allCurrencyData);
       writeNamesMethodNative(writer, currencies, allCurrencyData);
     }
     writer.commit(logger);
   }
   return packageName + "." + className;
 }
  public void build(
      TreeLogger logger, SourceBuilder<ModelMagic> builder, GeneratorContext ctx, JClassType type)
      throws UnableToCompleteException {

    ModelMagic models = builder.getPayload();
    ModelGenerator generator = new ModelGenerator(builder);
    // Step one; determine if we already have a concrete type or not.
    // TODO if JClassType is final, we need to wrap it using a delegate model.
    JClassType concrete;
    //    ClassBuffer cb = builder.getClassBuffer();
    JClassType root = models.getRootType(logger, ctx);
    if (type.isInterface() == null && type != root) {
      concrete = type;
      generator.setSuperClass(type.getQualifiedSourceName());
    } else {
      // We have an interface on our hands; search for an existing or
      // buildable model.
      // search for a supertype to inherit. Anything that extends Model,
      // does not implement any method we do implement, preferred type
      // being the one that implements the most interfaces possible
      final JClassType model;
      try {
        model = ctx.getTypeOracle().getType(Model.class.getName());
      } catch (NotFoundException e) {
        logger.log(
            Type.ERROR,
            "Cannot load "
                + Model.class.getName()
                + "; "
                + "make sure you have xapi-gwt-model:sources.jar on classpath.");
        throw new UnableToCompleteException();
      }
      concrete = model;
      for (JClassType supertype : concrete.getFlattenedSupertypeHierarchy()) {
        // Only interfaces explicitly extending Model become concrete.
        if (ModelGeneratorGwt.canBeSupertype(type, supertype)) {
          // prefer the concrete type with the most methods in common.
          concrete = supertype;
        }
      }
      if (concrete == null || concrete == model) {
        concrete = models.getRootType(logger, ctx);
        generator.setSuperClass(concrete.getQualifiedSourceName());
      } else {
        // We have to make sure this concrete supertype is created.
        if (!models.hasModel(concrete.getQualifiedSourceName())) {
          // Concrete type is not cached.  Build it now.
          RebindResult result =
              ModelGeneratorGwt.execImpl(logger, ctx, concrete.getQualifiedSourceName());
          generator.setSuperClass(result.getResultTypeName());
        }
      }
    }

    // This will probably become jsni, if we can avoid jso interface sickness...
    generator.createFactory(type.getQualifiedSourceName());

    HasModelFields fieldMap = new HasModelFields();
    fieldMap.setDefaultSerializable(type.getAnnotation(Serializable.class));

    for (JMethod method : methods.keySet()) {
      if (!toGenerate.contains(ModelGeneratorGwt.toSignature(method))) {
        logger.log(
            Type.TRACE, "Skipping method defined in supertype: " + method.getJsniSignature());
        continue;
      }

      Annotation[] annos = methods.get(method);
      String methodName = method.getName();
      String returnType = method.getReturnType().getQualifiedSourceName();
      String params = ModelGeneratorGwt.typeToParameterString(method.getParameterTypes());

      // TODO: check imports if we are safe to use simple name.
      returnType = method.getReturnType().getSimpleSourceName();
      IsType returns = X_Source.binaryToSource(method.getReturnType().getQualifiedBinaryName());
      IsType[] parameters = ModelGeneratorGwt.toTypes(method.getParameterTypes());

      GetterFor getter = method.getAnnotation(GetterFor.class);
      if (getter != null) {
        String name = getter.value();
        if (name.length() == 0) {
          name = ModelUtil.stripGetter(method.getName());
        }
        ModelField field = fieldMap.getOrMakeField(name);
        field.setType(returnType);
        assert parameters.length == 0
            : "A getter method cannot have parameters. "
                + "Generated code requires using getter methods without args.  You provided "
                + method.getJsniSignature();
        grabAnnotations(logger, models, fieldMap, method, annos, type);
        field.addGetter(returns, methodName);
        continue;
      }
      SetterFor setter = method.getAnnotation(SetterFor.class);
      if (setter != null) {
        String name = setter.value();
        if (name.length() == 0) name = ModelUtil.stripSetter(method.getName());
        grabAnnotations(logger, models, fieldMap, method, annos, type);
        continue;
      }

      if (method.getAnnotation(DeleterFor.class) != null) {
        implementAction(logger, generator, method, models, annos);
        continue;
      }

      // No annotation.  We have to guess the type.

      boolean isVoid = method.getReturnType().isPrimitive() == JPrimitiveType.VOID;
      boolean isGetter =
          methodName.startsWith("get")
              || methodName.startsWith("is")
              || methodName.startsWith("has");
      boolean isSetter, isAction;
      if (isGetter) {
        assert !isVoid
            : "Cannot have a void return type with method name "
                + methodName
                + "; getter prefixes get(), is() and has() must return a type.";
        isSetter = false;
        isAction = false;
      } else {
        isSetter =
            methodName.startsWith("set")
                || methodName.startsWith("add")
                || methodName.startsWith("put")
                || methodName.startsWith("rem")
                || methodName.startsWith("remove");
        if (isSetter) {
          isAction = false;
        } else {
          isAction = true;
        }
      }

      if (isVoid) {
        // definitely a setter / action method.
        if (isSetter) {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementSetter(logger, mb, method, models, fieldMap, annos);
        } else if (isAction) {
          implementAction(logger, generator, method, models, annos);
        } else {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementException(logger, mb, method);
        }
      } else {
        if (isGetter) {
          String name = ModelUtil.stripGetter(method.getName());
          ModelField field = fieldMap.getOrMakeField(name);
          field.setType(returnType);
          field.addGetter(returns, methodName);
          grabAnnotations(logger, models, fieldMap, method, annos, type);
        } else if (isSetter) {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementSetter(logger, mb, method, models, fieldMap, annos);
        } else if (isAction) {
          implementAction(logger, generator, method, models, annos);
        } else {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementException(logger, mb, method);
        }
      }
    }
    generator.generateModel(
        X_Source.toType(builder.getPackage(), builder.getClassBuffer().getSimpleName()), fieldMap);
  }
 private PropertyOracle mockPropertyOracle() {
   when(context.getPropertyOracle()).thenReturn(propertyOracle);
   return propertyOracle;
 }
  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();
  }
  private String buildRpcInterfaces(
      TreeLogger logger, GeneratorContext context, RequestQueueModel model) {
    String rqType = model.getRequestQueueInterfaceName();
    int lastDot = rqType.lastIndexOf('.');
    String packageName = rqType.substring(0, lastDot - 1);
    String serviceSourceName = rqType.substring(lastDot).replace('.', '_') + "_ImplRPC";
    String asyncSourceName = serviceSourceName + "Async";
    PrintWriter pw = context.tryCreate(logger, packageName, asyncSourceName);
    if (pw == null) {
      return packageName + "." + serviceSourceName;
    }

    // Create async class
    ClassSourceFileComposerFactory factory =
        new ClassSourceFileComposerFactory(packageName, asyncSourceName);
    factory.addImplementedInterface(ServiceQueueBaseAsync.class.getName());
    factory.makeInterface();
    SourceWriter asyncSw = factory.createSourceWriter(context, pw);

    // Create service class
    pw = context.tryCreate(logger, packageName, serviceSourceName);
    assert pw != null;
    factory = new ClassSourceFileComposerFactory(packageName, serviceSourceName);
    factory.addImplementedInterface(ServiceQueueBase.class.getName());
    factory.makeInterface();
    SourceWriter serviceSw = factory.createSourceWriter(context, pw);

    // write out service and async
    int i = 0;
    for (AsyncServiceModel service : model.getServices()) {
      for (AsyncServiceMethodModel method : service.getMethods()) {
        String methodName = "a" + ++i;
        asyncSw.println("void %1$s(", methodName);
        serviceSw.println("%2$s %1$s(", methodName, method.getReturnTypeName());
        asyncSw.indent();
        serviceSw.indent();

        boolean firstArgument = true;
        int argIndex = 0;
        for (JType arg : method.getArgTypes()) {
          if (!firstArgument) {
            asyncSw.println(",");
            serviceSw.println(",");
          }
          firstArgument = false;

          if (arg.isPrimitive() != null) {
            JPrimitiveType t = arg.isPrimitive();
            asyncSw.println("%2$s arg%1$d", argIndex, t.getQualifiedBoxedSourceName());
            serviceSw.println("%2$s arg%1$d", argIndex, t.getQualifiedBoxedSourceName());
          } else {
            asyncSw.println("%2$s arg%1$d", argIndex, arg.getParameterizedQualifiedSourceName());
            serviceSw.println("%2$s arg%1$d", argIndex, arg.getParameterizedQualifiedSourceName());
          }

          argIndex++;
        }
        if (!firstArgument) {
          asyncSw.print(", ");
        }
        // TODO return type boxing
        asyncSw.println(
            "%1$s<%2$s>callback);", AsyncCallback.class.getName(), method.getReturnTypeName());
        serviceSw.print(")");
        if (!method.getThrowables().isEmpty()) {
          serviceSw.print(" throws ");
          boolean firstThrowable = true;
          for (JClassType throwable : method.getThrowables()) {
            if (!firstThrowable) {
              serviceSw.print(", ");
            }
            firstThrowable = false;
            serviceSw.print(throwable.getQualifiedSourceName());
          }
        }
        serviceSw.println(";");
        asyncSw.outdent();
        serviceSw.outdent();
      }
    }

    asyncSw.commit(logger);
    serviceSw.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();
  }
  protected void tryWriteMetaInf(
      TreeLogger logger, Class<?> cls, JClassType impl, GeneratorContext context) {
    String serviceInterface = cls.getName();
    String serviceImplementation = impl.getQualifiedBinaryName();
    ArrayList<File> outputDirs = new ArrayList<File>();
    PropertyOracle properties = context.getPropertyOracle();
    try {
      File root = new File("");
      if (root.getAbsolutePath().endsWith("war"))
        root = new File(root.getAbsolutePath().replace(separator + "war", "") + separator);
      else root = new File(root.getAbsolutePath());
      ConfigurationProperty output = properties.getConfigurationProperty("xinject.output.dir");
      for (String dir : output.getValues()) {
        File f = new File(root, dir);
        if (f.isDirectory()) {
          outputDirs.add(f);
          f = new File(f, "META-INF" + separator + "services");
          if (!f.exists()) {
            if (!f.mkdirs()) {
              logger.log(
                  Type.WARN,
                  "Unable to create META-INF"
                      + separator
                      + "services "
                      + " in "
                      + f.getAbsolutePath()
                      + " "
                      + "Please ensure this directory exists, and is writable.");
            }
          }
        } else {
          logger.log(
              Type.WARN,
              "Missing xinject output directory: "
                  + f.getAbsolutePath()
                  + ". "
                  + "Please set xinject.output.dir to existing source directories; current value: "
                  + output.getValues());
        }
      }
    } catch (BadPropertyValueException e1) {
      logger.log(Type.WARN, "Unexpected propery exception for xinject.output.dir", e1);
    }
    try {
      String prefix =
          ".."
              + separator
              + "WEB-INF"
              + separator
              + "classes"
              + separator
              + "META-INF"
              + separator
              + "singletons"
              + separator;
      // TODO use a typed artifact to let the linker have a peak if it needs to
      OutputStream res = context.tryCreateResource(logger, prefix + serviceInterface);
      res.write(serviceImplementation.getBytes());
      context.commitResource(logger, res).setVisibility(Visibility.Public);
    } catch (UnableToCompleteException e) {
      logger.log(Type.ERROR, "Couldn't write java services to META-INF/singeltons", e);
    } catch (IOException e) {
      logger.log(
          Type.ERROR,
          "Couldn't write java services to META-INF/singletons; please ensure the war folder has full write access and the disk is not full.",
          e);
      e.printStackTrace();
    }

    logger.log(
        Type.TRACE,
        "Saving META-INF/singletons for " + serviceInterface + " -> " + serviceImplementation);
    exports:
    for (File output : outputDirs) {
      String knownContent = null;
      // check for existing META-INF/singletons entries, so we don't clobber anything
      File existing =
          new File(output, "META-INF" + separator + "services" + separator + serviceInterface);
      logger.log(Type.TRACE, "Saving ServiceLoader descriptor to " + existing.getAbsolutePath());
      if (existing.isFile()) {
        // need to read in existing manifest, and skip if service already exists
        BufferedReader reader = null;
        FileInputStream in = null;
        try {
          in = new FileInputStream(existing);
          reader = new BufferedReader(new InputStreamReader(in));

          String line;
          StringBuilder b = new StringBuilder();
          while ((line = reader.readLine()) != null) {
            if (line.equals(serviceImplementation)) {
              // the service impl already exists; skip to next output dir
              // TODO put in a flag to override top permission.
              try {
                ConfigurationProperty prop =
                    context
                        .getPropertyOracle()
                        .getConfigurationProperty("xinject.overwrite.existing");
                List<String> values = prop.getValues();
                if (values.size() > 0)
                  if (values.get(0).matches("true")) {
                    // if we're supposed to overwrite the value, but it's already on top
                    if (b.length() == 0) {
                      continue exports; // skip the file write
                    }
                    continue; // this erases the existing value so we can put it back over top.
                    // it also skips the breaking-continue below.
                  }
              } catch (BadPropertyValueException e) {
                logger.log(Type.TRACE, "", e);
              }
              // if we've found the service, and are not allowed to move it to top,
              continue exports; // carry on in the loop above.
            }
            b.append(line + "\n");
          }
          knownContent = b.toString().substring(0, b.length() - 1);
        } catch (IOException e) {
          logger.log(
              Type.WARN,
              "Received io exception writing META-INF/service for " + existing.getAbsolutePath());
        } finally {
          try {

            if (in != null) in.close();
            if (reader != null) reader.close();
          } catch (IOException e) {
          }
        }
      }
      // save a new java service descriptor
      FileWriter writer = null;
      try {
        try {
          boolean exists = existing.isFile();
          if (!exists) {
            if (!existing.createNewFile()) {
              logger.log(Type.WARN, "Could not create output file for " + existing);
              continue exports;
            }
          }
          writer = new FileWriter(existing, false);
          if (knownContent == null) {
            writer.append(serviceImplementation);
          } else {
            writer.append(serviceImplementation);
            writer.append('\n');
            writer.append(knownContent);
          }
        } finally {
          if (writer != null) {
            writer.close();
          }
        }
      } catch (IOException e) {
        logger.log(
            Type.WARN,
            "File write exception trying to save META-INF/singletons for " + existing,
            e);
      }
    }
  }
  public static InjectionCallbackArtifact ensureAsyncInjected(
      TreeLogger logger,
      String packageName,
      String className,
      String outputClass,
      GeneratorContext ctx)
      throws UnableToCompleteException {

    GwtInjectionMap gwtInjectionMap = getInjectionMap(logger, ctx);
    InjectionCallbackArtifact artifact =
        gwtInjectionMap.getOrCreateArtifact(ctx, packageName, className);
    if (artifact.isTargetUnbound()) {
      artifact.bindTo(outputClass);
      ensureProviderClass(
          logger,
          packageName,
          artifact.getSimpleName(),
          artifact.getCanonicalName(),
          artifact.getBoundTarget(),
          ctx);
      logger =
          logger.branch(
              Type.TRACE,
              "Creating asynchronous callback for "
                  + artifact.getCanonicalName()
                  + " -> "
                  + outputClass);
      String generatedName = InjectionUtils.generatedAsyncProviderName(artifact.getGeneratedName());
      String implPackage = artifact.getImplementationPackage();
      PrintWriter printWriter = ctx.tryCreate(logger, implPackage, generatedName);
      if (printWriter == null) {
        logger.log(
            Type.WARN,
            "Could not create the source writer for " + implPackage + "." + generatedName);
        return artifact;
      }
      artifact.addCallback(implPackage + "." + generatedName + ".Deproxy");
      ctx.commitArtifact(logger, artifact);

      ClassSourceFileComposerFactory composer =
          new ClassSourceFileComposerFactory(implPackage, generatedName);
      composer.setPrivacy("public final");

      composer.addImport(com.google.gwt.core.client.GWT.class.getName());
      composer.addImport(RunAsyncCallback.class.getName());
      composer.addImport(Fifo.class.getName());
      composer.addImport(JsFifo.class.getName());
      composer.addImport(AsyncProxy.class.getName());
      composer.addImport(ApplyMethod.class.getName());
      composer.addImport(ReceivesValue.class.getName());
      composer.addImport(ReceiverAdapter.class.getCanonicalName());
      composer.addImport(artifact.getCanonicalName());

      String simpleName = artifact.getSimpleName();
      SourceWriter sw = composer.createSourceWriter(ctx, printWriter);

      sw.println();
      sw.println("static final class Callbacks implements ApplyMethod{");
      sw.indent();
      sw.println("public void apply(Object ... args){");
      sw.println("}");
      sw.outdent();
      sw.println("}");
      sw.println();

      sw.println("static final class Deproxy implements ReceivesValue<" + simpleName + ">{");
      sw.indent();
      sw.println("public final void set(final " + simpleName + " value){");
      sw.indentln("getter = new ReceiverAdapter<" + simpleName + ">(value);");
      sw.println("}");
      sw.outdent();
      sw.println("}");
      sw.println();

      sw.println(
          "private static final class Proxy implements ReceivesValue<ReceivesValue<"
              + simpleName
              + ">>{");
      sw.indent();
      sw.println("public final void set(final ReceivesValue<" + simpleName + "> receiver){");
      sw.indent();

      sw.print("GWT.runAsync(");
      sw.println(artifact.getCanonicalName() + ".class,new Request(receiver));");

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

      sw.println("private static final class Request");
      sw.indent();
      sw.println("extends AsyncProxy<" + simpleName + "> ");
      sw.println("implements RunAsyncCallback{");

      DefermentWriter defer = new DefermentWriter(sw);
      defer.setStrategy(DefermentStrategy.NONE);

      sw.println("private static final Fifo<ReceivesValue<" + simpleName + ">> pending =");
      sw.indentln("JsFifo.newFifo();");
      sw.println();

      sw.println("protected Request(ReceivesValue<" + simpleName + "> receiver){");
      sw.indentln("accept(receiver);");
      sw.println("}");
      sw.println();

      sw.println("@Override");
      sw.println("protected final Fifo<ReceivesValue<" + simpleName + ">> pending(){");
      sw.indentln("return pending;");
      sw.println("}");
      sw.println();

      sw.println("protected final void dispatch(){");
      sw.indentln("go();");
      sw.println("}");
      sw.println();

      sw.println("public final void onSuccess(){");
      sw.indent();
      defer.printStart();

      sw.println("final " + simpleName + " value = ");
      sw.print(packageName + "." + InjectionUtils.generatedProviderName(simpleName));
      sw.println(".theProvider.get();");
      sw.println();

      sw.print("final ApplyMethod callbacks = GWT.create(");
      sw.print(packageName + ".impl." + generatedName + ".Callbacks.class");
      sw.println(");");
      sw.println("callbacks.apply(value);");
      sw.println();

      sw.println("apply(value);");
      sw.outdent();
      sw.println("}");
      sw.outdent();
      defer.printFinish();
      sw.println("}");
      sw.println();

      sw.println(
          "private static ReceivesValue<ReceivesValue<" + simpleName + ">> getter = new Proxy();");
      sw.println();

      sw.println("static void request(final ReceivesValue<" + simpleName + "> request){");
      sw.indentln("getter.set(request);");
      sw.println("}");
      sw.println();

      sw.println("static void go(){");
      sw.indentln("request(null);");
      sw.println("}");
      sw.println();

      sw.println("private " + generatedName + "(){}");

      sw.commit(logger);

    } else {
      assert artifact.getBoundTarget().equals(outputClass)
          : "The injection target "
              + artifact.getCanonicalName()
              + " was bound "
              + "to "
              + artifact.getBoundTarget()
              + ", but you tried to bind it again, "
              + "to a different class: "
              + outputClass;
    }
    return artifact;
  }
  public String generate(TreeLogger logger, GeneratorContext context, String typeName)
      throws UnableToCompleteException {
    // .println("Introspector Generate.");
    try {
      this.objectType = context.getTypeOracle().getType("java.lang.Object");
    } catch (NotFoundException ex) {
      logger.log(TreeLogger.ERROR, typeName, ex);

      return null;
    }

    List<BeanResolver> introspectables =
        this.getIntrospectableTypes(logger, context.getTypeOracle());

    MethodWrapper[] methods = this.findMethods(logger, introspectables);

    ClassSourceFileComposerFactory mcf =
        new ClassSourceFileComposerFactory(this.packageName, this.methodsImplementationName);
    mcf.addImport(Method.class.getCanonicalName());

    PrintWriter methodsPrintWriter =
        context.tryCreate(logger, this.packageName, this.methodsImplementationName);

    if (methodsPrintWriter != null) {
      SourceWriter methodsWriter = mcf.createSourceWriter(context, methodsPrintWriter);
      this.writeMethods(logger, methods, methodsWriter);
      methodsWriter.println("}");
      context.commit(logger, methodsPrintWriter);
    }

    ClassSourceFileComposerFactory cfcf =
        new ClassSourceFileComposerFactory(this.packageName, this.implementationName);
    cfcf.addImplementedInterface(typeName);
    cfcf.addImport("java.util.HashMap");
    cfcf.addImport(Method.class.getCanonicalName());
    cfcf.addImport(com.totsp.gwittir.introspection.Property.class.getCanonicalName());
    cfcf.addImport(com.totsp.gwittir.introspection.BeanDescriptor.class.getCanonicalName());

    PrintWriter printWriter = context.tryCreate(logger, packageName, implementationName);

    if (printWriter == null) {
      // .println( "Introspector Generate skipped.");
      return packageName + "." + implementationName;
    }

    SourceWriter writer = cfcf.createSourceWriter(context, printWriter);
    this.writeIntrospectables(logger, introspectables, methods, writer);
    this.writeResolver(introspectables, writer);

    writer.println(
        "private HashMap<Class,BeanDescriptor> beanDescriptorLookup = new HashMap<Class,BeanDescriptor>();");
    writer.println();
    writer.println("public BeanDescriptor getDescriptor( Object object ){ ");
    writer.indent();
    writer.println(
        "if( object == null ) throw new NullPointerException(\"Attempt to introspect null object\");");
    writer.println(
        "if( object instanceof "
            + SelfDescribed.class.getCanonicalName()
            + " ) return ((SelfDescribed)object).__descriptor();");
    writer.println("BeanDescriptor descriptor = beanDescriptorLookup.get(object.getClass());");
    writer.println("if (descriptor!=null){");
    writer.indentln("return descriptor;");
    writer.outdent();
    writer.println("}");

    writer.println("descriptor=_getDescriptor(object);");
    writer.println("beanDescriptorLookup.put(object.getClass(),descriptor);");
    writer.println("return descriptor;");
    writer.outdent();
    writer.println("}");

    writer.println("private BeanDescriptor _getDescriptor( Object object ){ ");
    writer.indent();

    for (BeanResolver resolver : introspectables) {
      writer.println(
          "if( object instanceof " + resolver.getType().getQualifiedSourceName() + " ) {");
      writer.indent();

      String name = resolver.getType().getQualifiedSourceName().replaceAll("\\.", "_");
      logger.log(TreeLogger.DEBUG, "Writing : " + name, null);
      writer.print("return " + name + " == null ? " + name + " = ");
      this.writeBeanDescriptor(logger, resolver, methods, writer);
      writer.print(": " + name + ";");
      writer.outdent();
      writer.println("}");
    }

    writer.println(" throw new IllegalArgumentException(\"Unknown type\" + object.getClass() ); ");
    writer.outdent();
    writer.println("}");
    writer.println("public Object createInstance(Class clazz) {");
    writer.indent();
    for (BeanResolver resolver : introspectables) {
      boolean hasPNA = false;
      for (JConstructor constructor : resolver.getType().getConstructors()) {
        if (constructor.getParameters() == null
            || constructor.getParameters().length == 0 && constructor.isPublic()) {
          hasPNA = true;
          break;
        }
        if (hasPNA) {
          break;
        }
      }

      writer.println(
          "if(clazz.equals(" + resolver.getType().getQualifiedSourceName() + ".class)){");
      writer.indent();
      logger.log(
          TreeLogger.Type.TRACE,
          resolver.getType().getQualifiedSourceName()
              + " abstract "
              + resolver.getType().isAbstract()
              + " intf "
              + (resolver.getType().isInterface() != null)
              + " def "
              + resolver.getType().isDefaultInstantiable());
      if (resolver.getType().isAbstract() || resolver.getType().isInterface() != null) {
        writer.println("throw new IllegalArgumentException(clazz+\" is abstract\");");
      } else if (hasPNA) {
        writer.println("return new " + resolver.getType().getQualifiedSourceName() + "();");
      } else {
        writer.println(
            "throw new IllegalArgumentException(clazz+\" has no public no args constructor\");");
      }
      writer.outdent();
      writer.println("}");
    }
    writer.println(" throw new IllegalArgumentException(\"Unknown type\" +clazz ); ");
    writer.outdent();
    writer.println("}");

    writer.println("HashMap<String, Class> classes = new HashMap<String, Class>();");
    writer.println("public Class forName(String className){");
    writer.indent();
    writer.println("Class clazz = classes.get(className);");
    writer.println("if(clazz != null) return clazz;");
    for (BeanResolver resolver : introspectables) {
      writer.println(
          "if(className.equals(\"" + resolver.getType().getQualifiedSourceName() + "\")){");
      writer.indent();
      writer.println("clazz = " + resolver.getType().getQualifiedSourceName() + ".class;");
      writer.println("classes.put(className, clazz);");
      writer.println("return clazz;");
      writer.outdent();
      writer.println("}");
    }
    writer.println("throw new IllegalArgumentException(className+\" is not introspecable.\");");
    writer.outdent();
    writer.println("}");
    writer.outdent();
    writer.println("}");

    context.commit(logger, printWriter);

    // .println( "Introspector Generate completed.");
    return packageName + "." + implementationName;
  }
Exemple #24
0
  /**
   * @param logger
   * @param context
   * @param typeName
   * @param gr
   * @return
   */
  public boolean isGenerate(
      TreeLogger logger, GeneratorContext context, String typeName, GenPredicGroup gr) {
    boolean result = false;
    if ((gr.getMyGroups() != null) && (gr.getMyGroups().size() > 0)) {
      for (GenPredicGroup group : gr.getMyGroups()) {
        switch (gr.getOperator()) {
          case ANY:
            result = result || isGenerate(logger, context, typeName, group);
            break;
          case NONE:
            result = !isGenerate(logger, context, typeName, group);
            if (!result) return false;
            break;
          case ALL:
            result = isGenerate(logger, context, typeName, group);
            if (!result) return false;
          default:
            break;
        }
      }
    }
    if ((gr.getGeneratorPredicts() != null) && (gr.getGeneratorPredicts().size() > 0)) {
      for (GeneratorPredicate entry : gr.getGeneratorPredicts()) {
        String value = null;
        try {
          switch (entry.getEPredict()) {
            case ASSIGNABLE:
              if (context
                  .getTypeOracle()
                  .findType(typeName)
                  .isAssignableTo(context.getTypeOracle().getType(entry.getValue()))) {
                value = entry.getValue();
              } else {
                value = typeName;
              }
              break;
            case TYPEIS:
              value = typeName;
              break;
            case PROPERTY:
              // ???he
              value =
                  context
                      .getPropertyOracle()
                      .getSelectionProperty(logger, entry.getName())
                      .getCurrentValue();
              break;
            default:
              value = null;
              break;
          }
        } catch (Exception e) {
          value = null;
          result = false;
        }

        if (value != null) {
          switch (gr.getOperator()) {
            case ANY:
              result = result || entry.getValue().equals(value);
              break;
            case NONE:
              result = !entry.getValue().equals(value);
              if (!result) return false;
              break;
            case ALL:
              result = entry.getValue().equals(value);
              if (!result) return false;
            default:
              break;
          }
        }
      }
    }
    return result;
  }
 public void commit() {
   for (PrintWriter writer : writers) {
     generatorContext.commit(logger, writer);
   }
 }
 /**
  * Generate a class which can select between alternate implementations at runtime based on the
  * runtime locale.
  *
  * @param logger TreeLogger instance for log messages
  * @param context GeneratorContext for generating source files
  * @param targetClass class to generate
  * @param compileLocale the compile-time locale we are generating for
  * @param locales set of all locales to generate
  * @return fully-qualified class name that was generated
  */
 private String generateRuntimeSelection(
     TreeLogger logger,
     GeneratorContext context,
     JClassType targetClass,
     GwtLocale compileLocale,
     Set<GwtLocale> locales) {
   String packageName = targetClass.getPackage().getName();
   String className =
       targetClass.getName().replace('.', '_')
           + "_"
           + compileLocale.getAsString()
           + "_runtimeSelection";
   PrintWriter pw = context.tryCreate(logger, packageName, className);
   if (pw != null) {
     ClassSourceFileComposerFactory factory =
         new ClassSourceFileComposerFactory(packageName, className);
     factory.setSuperclass(targetClass.getQualifiedSourceName());
     factory.addImport(CURRENCY_DATA);
     factory.addImport(JAVASCRIPTOBJECT);
     factory.addImport(HASHMAP);
     factory.addImport("com.google.gwt.i18n.client.LocaleInfo");
     SourceWriter writer = factory.createSourceWriter(context, pw);
     writer.println("private CurrencyList instance;");
     writer.println();
     writer.println("@Override");
     writer.println("protected CurrencyData getDefaultJava() {");
     writer.println("  ensureInstance();");
     writer.println("  return instance.getDefaultJava();");
     writer.println("}");
     writer.println();
     writer.println("@Override");
     writer.println("protected CurrencyData getDefaultNative() {");
     writer.println("  ensureInstance();");
     writer.println("  return instance.getDefaultNative();");
     writer.println("}");
     writer.println();
     writer.println("@Override");
     writer.println("protected HashMap<String, CurrencyData> loadCurrencyMapJava() {");
     writer.println("  ensureInstance();");
     writer.println("  return instance.loadCurrencyMapJava();");
     writer.println("}");
     writer.println();
     writer.println("@Override");
     writer.println("protected JavaScriptObject loadCurrencyMapNative() {");
     writer.println("  ensureInstance();");
     writer.println("  return instance.loadCurrencyMapNative();");
     writer.println("}");
     writer.println();
     writer.println("@Override");
     writer.println("protected HashMap<String, String> loadNamesMapJava() {");
     writer.println("  ensureInstance();");
     writer.println("  return instance.loadNamesMapJava();");
     writer.println("}");
     writer.println();
     writer.println("@Override");
     writer.println("protected JavaScriptObject loadNamesMapNative() {");
     writer.println("  ensureInstance();");
     writer.println("  return instance.loadNamesMapNative();");
     writer.println("}");
     writer.println();
     writer.println("private void ensureInstance() {");
     writer.indent();
     writer.println("if (instance != null) {");
     writer.println("  return;");
     writer.println("}");
     boolean fetchedLocale = false;
     Map<String, Set<GwtLocale>> localeMap = new TreeMap<String, Set<GwtLocale>>();
     String compileLocaleClass =
         processChildLocale(logger, context, targetClass, localeMap, compileLocale);
     if (compileLocaleClass == null) {
       // already gave warning, just use default implementation
       return null;
     }
     for (GwtLocale runtimeLocale : locales) {
       processChildLocale(logger, context, targetClass, localeMap, runtimeLocale);
     }
     for (Entry<String, Set<GwtLocale>> entry : localeMap.entrySet()) {
       if (!fetchedLocale) {
         writer.println("String runtimeLocale = LocaleInfo.getCurrentLocale().getLocaleName();");
         fetchedLocale = true;
       }
       boolean firstLocale = true;
       String generatedClass = entry.getKey();
       if (compileLocaleClass.equals(generatedClass)) {
         // The catch-all will handle this
         continue;
       }
       writer.print("if (");
       for (GwtLocale locale : entry.getValue()) {
         if (firstLocale) {
           firstLocale = false;
         } else {
           writer.println();
           writer.print("    || ");
         }
         writer.print("\"" + locale.toString() + "\".equals(runtimeLocale)");
       }
       writer.println(") {");
       writer.println("  instance = new " + generatedClass + "();");
       writer.println("  return;");
       writer.println("}");
     }
     writer.println("instance = new " + compileLocaleClass + "();");
     writer.outdent();
     writer.println("}");
     writer.commit(logger);
   }
   return packageName + "." + className;
 }
  @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();
  }