예제 #1
0
파일: GWTUtil.java 프로젝트: snjeza/errai
  /**
   * 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);
  }
예제 #2
0
  /**
   * Given a UiBinder interface, return the path to its ui.xml file, suitable for any classloader to
   * find it as a resource.
   */
  private static String deduceTemplateFile(MortalLogger logger, JClassType interfaceType)
      throws UnableToCompleteException {
    String templateName = null;
    UiTemplate annotation = interfaceType.getAnnotation(UiTemplate.class);
    if (annotation == null) {
      // if the interface is defined as a nested class, use the name of the
      // enclosing type
      if (interfaceType.getEnclosingType() != null) {
        interfaceType = interfaceType.getEnclosingType();
      }
      return slashify(interfaceType.getQualifiedBinaryName()) + TEMPLATE_SUFFIX;
    } else {
      templateName = annotation.value();
      if (!templateName.endsWith(TEMPLATE_SUFFIX)) {
        logger.die("Template file name must end with " + TEMPLATE_SUFFIX);
      }

      /*
       * If the template file name (minus suffix) has no dots, make it relative
       * to the binder's package, otherwise slashify the dots
       */
      String unsuffixed = templateName.substring(0, templateName.lastIndexOf(TEMPLATE_SUFFIX));
      if (!unsuffixed.contains(".")) {
        templateName = slashify(interfaceType.getPackage().getName()) + "/" + templateName;
      } else {
        templateName = slashify(unsuffixed) + TEMPLATE_SUFFIX;
      }
    }
    return templateName;
  }
 @Override
 protected LoadStyle getLoadStyle(final JClassType connectorType) {
   if (eagerConnectors.contains(connectorType.getQualifiedBinaryName())) {
     return LoadStyle.EAGER;
   } else {
     // Loads all other connectors immediately after the initial view has
     // been rendered
     return LoadStyle.DEFERRED;
   }
 }
예제 #4
0
  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);
      }
    }
  }