Tuesday, September 12, 2017

How do you use GWT "Genertor" class?

Hi there,

I have questions about this "Generator" class below. The code below is the one that generate the GWT Sample page, that you can see here http://samples.gwtproject.org/samples/Showcase/Showcase.html#!CwCheckBox.
I have been looking at such code for some time now. I notice it would generate many Java.html files, in this location "/war/showcase/gwtShowcaseSource".

My questions to you are below.

1. If I export the project that uses this "Generator" class as the war file, and upload such war file to Tomcat server, when the users use the website, will they be able to read the source code? I really don't want any users that come to my website to be able to view any Java source code, because of the safety issue.

2. Why would anyone want to use this "Generator" class to generate another set of Java source code? I am guessing, at this point, that you would do this if you want to implement "GWT Localization" such as supporting multiple languages. But, then, you would be generating source code for people to see.

3. I hope someone can explain to me the life cycle of this "Generator" class. From how I understand it, during the "Dev" mode, using Eclipse, it would be compiled by Java Virtual Machine. However, once you export the project as the war file and upload it to the server, it would be used as Javascript library. But why you would need to include these raw files within the war file?

4. Would any of the raw files be downloaded to the users' hard disks or the browser's cookie?

Thank you.

/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.sample.showcase.generator;

import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.Showcase;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseRaw;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
import com.google.gwt.sample.showcase.client.ShowcaseConstants;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * Generate the source code, css styles, and raw source used in the Showcase
 * examples.
 */
public class ShowcaseGenerator extends Generator {
  /**
   * The paths to the CSS style sheets used in Showcase. The paths are relative
   * to the root path of the {@link ClassLoader}. The variable $THEME will be
   * replaced by the current theme. The variable $RTL will be replaced by "_rtl"
   * for RTL locales.
   */
  private static final String[] SRC_CSS = {
      "com/google/gwt/user/theme/$THEME/public/gwt/$THEME/$THEME$RTL.css",
      "com/google/gwt/sample/showcase/client/Showcase.css"};

  /**
   * The class loader used to get resources.
   */
  private ClassLoader classLoader = null;

  /**
   * The generator context.
   */
  private GeneratorContext context = null;

  /**
   * The {@link TreeLogger} used to log messages.
   */
  private TreeLogger logger = null;

  /**
   * The set of raw files that have already been generated. Raw files can be
   * reused by different examples, but we only generate them once.
   */
  private Set<String> rawFiles = new HashSet<String>();

  @Override
  public String generate(
      TreeLogger logger, GeneratorContext context, String typeName)
      throws UnableToCompleteException {
    this.logger = logger;
    this.context = context;
    this.classLoader = Thread.currentThread().getContextClassLoader();

    // Only generate files on the first permutation
    if (!isFirstPass()) {
      return null;
    }

    // Get the Showcase ContentWidget subtypes to examine
    JClassType cwType = null;
    try {
      cwType = context.getTypeOracle().getType(ContentWidget.class.getName());
    } catch (NotFoundException e) {
      logger.log(TreeLogger.ERROR, "Cannot find ContentWidget class", e);
      throw new UnableToCompleteException();
    }
    JClassType[] types = cwType.getSubtypes();

    // Generate the source and raw source files
    for (JClassType type : types) {
      generateRawFiles(type);
      generateSourceFiles(type);
    }

    // Generate the CSS source files
    String[] themes = new String[]{Showcase.THEME};
    for (String theme : themes) {
      String styleDefsLTR = getStyleDefinitions(theme, false);
      String styleDefsRTL = getStyleDefinitions(theme, true);
      String outDirLTR = ShowcaseConstants.DST_SOURCE_STYLE + theme + "/";
      String outDirRTL = ShowcaseConstants.DST_SOURCE_STYLE + theme + "_rtl/";
      for (JClassType type : types) {
        generateStyleFiles(type, styleDefsLTR, outDirLTR);
        generateStyleFiles(type, styleDefsRTL, outDirRTL);
      }
    }

    return null;
  }

  /**
   * Set the full contents of a resource in the public directory.
   *
   * @param partialPath the path to the file relative to the public directory
   * @param contents the file contents
   */
  private void createPublicResource(String partialPath, String contents)
      throws UnableToCompleteException {
    try {
      OutputStream outStream = context.tryCreateResource(logger, partialPath);
      if (outStream == null) {
        String message = "Attempting to generate duplicate public resource: "
            + partialPath
            + ".\nAll generated source files must have unique names.";
        logger.log(TreeLogger.ERROR, message);
        throw new UnableToCompleteException();
      }
      outStream.write(contents.getBytes());
      context.commitResource(logger, outStream);
    } catch (IOException e) {
      logger.log(TreeLogger.ERROR, "Error writing file: " + partialPath, e);
      throw new UnableToCompleteException();
    }
  }

  /**
   * Generate the raw files used by a {@link ContentWidget}.
   *
   * @param type the {@link ContentWidget} subclass
   */
  private void generateRawFiles(JClassType type)
      throws UnableToCompleteException {
    // Look for annotation
    if (!type.isAnnotationPresent(ShowcaseRaw.class)) {
      return;
    }

    // Get the package info
    String pkgName = type.getPackage().getName();
    String pkgPath = pkgName.replace('.', '/') + "/";

    // Generate each raw source file
    String[] filenames = type.getAnnotation(ShowcaseRaw.class).value();
    for (String filename : filenames) {
      // Check if the file has already been generated.
      String path = pkgName + filename;
      if (rawFiles.contains(path)) {
        continue;
      }
      rawFiles.add(path);

      // Get the file contents
      String fileContents = getResourceContents(pkgPath + filename);

      // Make the source pretty
      fileContents = fileContents.replace("<", "&lt;");
      fileContents = fileContents.replace(">", "&gt;");
      fileContents = fileContents.replace("* \n   */\n", "*/\n");
      fileContents = "<pre>" + fileContents + "</pre>";

      // Save the raw source in the public directory
      String dstPath = ShowcaseConstants.DST_SOURCE_RAW + filename + ".html";
      createPublicResource(dstPath, fileContents);
    }
  }

  /**
   * Generate the formatted source code for a {@link ContentWidget}.
   *
   * @param type the {@link ContentWidget} subclass
   */
  private void generateSourceFiles(JClassType type)
      throws UnableToCompleteException {
    // Get the file contents
    String filename = type.getQualifiedSourceName().replace('.', '/') + ".java";
    String fileContents = getResourceContents(filename);

    // Get each data code block
    String formattedSource = "";
    String dataTag = "@" + ShowcaseData.class.getSimpleName();
    String sourceTag = "@" + ShowcaseSource.class.getSimpleName();
    int dataTagIndex = fileContents.indexOf(dataTag);
    int srcTagIndex = fileContents.indexOf(sourceTag);
    while (dataTagIndex >= 0 || srcTagIndex >= 0) {
      if (dataTagIndex >= 0
          && (dataTagIndex < srcTagIndex || srcTagIndex < 0)) {
        // Get the boundaries of a DATA tag
        int beginIndex = fileContents.lastIndexOf("  /*", dataTagIndex);
        int beginTagIndex = fileContents.lastIndexOf("\n", dataTagIndex) + 1;
        int endTagIndex = fileContents.indexOf("\n", dataTagIndex) + 1;
        int endIndex = fileContents.indexOf(";", beginIndex) + 1;

        // Add to the formatted source
        String srcData = fileContents.substring(beginIndex, beginTagIndex)
            + fileContents.substring(endTagIndex, endIndex);
        formattedSource += srcData + "\n\n";

        // Get next tag
        dataTagIndex = fileContents.indexOf(dataTag, endIndex + 1);
      } else {
        // Get the boundaries of a SRC tag
        int beginIndex = fileContents.lastIndexOf("/*", srcTagIndex) - 2;
        int beginTagIndex = fileContents.lastIndexOf("\n", srcTagIndex) + 1;
        int endTagIndex = fileContents.indexOf("\n", srcTagIndex) + 1;
        int endIndex = fileContents.indexOf("\n  }", beginIndex) + 4;

        // Add to the formatted source
        String srcCode = fileContents.substring(beginIndex, beginTagIndex)
            + fileContents.substring(endTagIndex, endIndex);
        formattedSource += srcCode + "\n\n";

        // Get the next tag
        srcTagIndex = fileContents.indexOf(sourceTag, endIndex + 1);
      }
    }

    // Make the source pretty
    formattedSource = formattedSource.replace("<", "&lt;");
    formattedSource = formattedSource.replace(">", "&gt;");
    formattedSource = formattedSource.replace("* \n   */\n", "*/\n");
    formattedSource = "<pre>" + formattedSource + "</pre>";

    // Save the source code to a file
    String dstPath = ShowcaseConstants.DST_SOURCE_EXAMPLE
        + type.getSimpleSourceName() + ".html";
    createPublicResource(dstPath, formattedSource);
  }

  /**
   * Generate the styles used by a {@link ContentWidget}.
   *
   * @param type the {@link ContentWidget} subclass
   * @param styleDefs the concatenated style definitions
   * @param outDir the output directory
   */
  private void generateStyleFiles(
      JClassType type, String styleDefs, String outDir)
      throws UnableToCompleteException {
    // Look for annotation
    if (!type.isAnnotationPresent(ShowcaseStyle.class)) {
      return;
    }

    // Generate a style file for each theme/RTL mode pair
    String[] prefixes = type.getAnnotation(ShowcaseStyle.class).value();
    Map<String, String> matched = new LinkedHashMap<String, String>();
    for (String prefix : prefixes) {
      // Get the start location of the style code in the source file
      boolean foundStyle = false;
      int start = styleDefs.indexOf("\n" + prefix);
      while (start >= 0) {
        // Get the cssContents string name pattern
        int end = styleDefs.indexOf("{", start);
        String matchedName = styleDefs.substring(start, end).trim();

        // Get the style code
        end = styleDefs.indexOf("}", start) + 1;
        String styleDef = "<pre>" + styleDefs.substring(start, end) + "</pre>";
        matched.put(matchedName, styleDef);

        // Goto the next match
        foundStyle = true;
        start = styleDefs.indexOf("\n" + prefix, end);
      }

      // No style exists
      if (!foundStyle) {
        matched.put(prefix, "<pre>" + prefix + " {\n}</pre>");
      }
    }

    // Combine all of the styles into one formatted string
    String formattedStyle = "";
    for (String styleDef : matched.values()) {
      formattedStyle += styleDef;
    }

    // Save the raw source in the public directory
    String dstPath = outDir + type.getSimpleSourceName() + ".html";
    createPublicResource(dstPath, formattedStyle);
  }

  /**
   * Get the full contents of a resource.
   *
   * @param path the path to the resource
   * @return the contents of the resource
   */
  private String getResourceContents(String path)
      throws UnableToCompleteException {
    InputStream in = classLoader.getResourceAsStream(path);
    if (in == null) {
      logger.log(TreeLogger.ERROR, "Resource not found: " + path);
      throw new UnableToCompleteException();
    }

    StringBuffer fileContentsBuf = new StringBuffer();
    BufferedReader br = null;
    try {
      br = new BufferedReader(new InputStreamReader(in));
      String temp;
      while ((temp = br.readLine()) != null) {
        fileContentsBuf.append(temp).append('\n');
      }
    } catch (IOException e) {
      logger.log(TreeLogger.ERROR, "Cannot read resource", e);
      throw new UnableToCompleteException();
    } finally {
      if (br != null) {
        try {
          br.close();
        } catch (IOException e) {
        }
      }
    }

    // Return the file contents as a string
    return fileContentsBuf.toString();
  }

  /**
   * Load the contents of all CSS files used in the Showcase for a given
   * theme/RTL mode, concatenated into one string.
   *
   * @param theme the style theme
   * @param isRTL true if RTL mode
   * @return the concatenated styles
   */
  private String getStyleDefinitions(String theme, boolean isRTL)
      throws UnableToCompleteException {
    String cssContents = "";
    for (String path : SRC_CSS) {
      path = path.replace("$THEME", theme);
      if (isRTL) {
        path = path.replace("$RTL", "_rtl");
      } else {
        path = path.replace("$RTL", "");
      }
      cssContents += getResourceContents(path) + "\n\n";
    }
    return cssContents;
  }

  /**
   * Ensure that we only generate files once by creating a placeholder file,
   * then looking for it on subsequent generates.
   *
   * @return true if this is the first pass, false if not
   */
  private boolean isFirstPass() {
    String placeholder = ShowcaseConstants.DST_SOURCE + "generated";
    try {
      OutputStream outStream = context.tryCreateResource(logger, placeholder);
      if (outStream == null) {
        return false;
      } else {
        context.commitResource(logger, outStream);
      }
    } catch (UnableToCompleteException e) {
      logger.log(TreeLogger.ERROR, "Unable to generate", e);
      return false;
    }
    return true;
  }
}

--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment