/**
   * Constructs a GroovyPageMetaInfo instance which holds the script class, modified date and so on
   *
   * @param inputStream The InputStream to construct the GroovyPageMetaInfo instance from
   * @param res The Spring Resource to construct the MetaInfo from
   * @param pageName The name of the page (can be null, in which case method responsible for
   *     calculating appropriate alternative)
   * @return The GroovyPageMetaInfo instance
   */
  protected GroovyPageMetaInfo buildPageMetaInfo(
      InputStream inputStream, Resource res, String pageName) {
    String name = establishPageName(res, pageName);

    long lastModified = establishLastModified(res);

    GroovyPageParser parser;
    String path = getPathForResource(res);
    try {
      parser = new GroovyPageParser(name, path, path, inputStream);
    } catch (IOException e) {
      throw new GroovyPagesException(
          "I/O parsing Groovy page ["
              + (res != null ? res.getDescription() : name)
              + "]: "
              + e.getMessage(),
          e);
    }
    InputStream in = parser.parse();

    // Make a new metaInfo
    GroovyPageMetaInfo metaInfo = createPageMetaInfo(parser, lastModified, in);
    try {
      metaInfo.setPageClass(compileGroovyPage(in, name, path, metaInfo));
      metaInfo.setHtmlParts(parser.getHtmlPartsArray());
    } catch (GroovyPagesException e) {
      metaInfo.setCompilationException(e);
    }

    if (!name.startsWith(GENERATED_GSP_NAME_PREFIX)) {
      pageCache.put(name, metaInfo);
    }

    return metaInfo;
  }
  /**
   * Attempts to compile the given InputStream into a Groovy script using the given name
   *
   * @param in The InputStream to read the Groovy code from
   * @param name The name of the class to use
   * @param pageName The page name
   * @param metaInfo
   * @return The compiled java.lang.Class, which is an instance of groovy.lang.Script
   */
  private Class<?> compileGroovyPage(
      InputStream in, String name, String pageName, GroovyPageMetaInfo metaInfo) {
    GroovyClassLoader groovyClassLoader = findOrInitGroovyClassLoader();

    // Compile the script into an object
    Class<?> scriptClass;
    try {
      scriptClass = groovyClassLoader.parseClass(DefaultGroovyMethods.getText(in), name);
    } catch (CompilationFailedException e) {
      LOG.error("Compilation error compiling GSP [" + name + "]:" + e.getMessage(), e);

      int lineNumber = GrailsExceptionResolver.extractLineNumber(e);

      final int[] lineMappings = metaInfo.getLineNumbers();
      if (lineNumber > 0 && lineNumber < lineMappings.length) {
        lineNumber = lineMappings[lineNumber - 1];
      }
      throw new GroovyPagesException(
          "Could not parse script [" + name + "]: " + e.getMessage(), e, lineNumber, pageName);
    } catch (IOException e) {
      throw new GroovyPagesException(
          "IO exception parsing script [" + name + "]: " + e.getMessage(), e);
    }
    return scriptClass;
  }
  /**
   * Creates a GroovyPageMetaInfo instance from the given Parse object, and initialises it with the
   * the specified last modifed date and InputStream
   *
   * @param parse The Parse object
   * @param lastModified The last modified date
   * @param in The InputStream instance
   * @return A GroovyPageMetaInfo instance
   */
  private GroovyPageMetaInfo createPageMetaInfo(
      GroovyPageParser parse, long lastModified, InputStream in) {
    GroovyPageMetaInfo pageMeta = new GroovyPageMetaInfo();
    pageMeta.setJspTagLibraryResolver(jspTagLibraryResolver);
    pageMeta.setTagLibraryLookup(tagLibraryLookup);
    pageMeta.setContentType(parse.getContentType());
    pageMeta.setLineNumbers(parse.getLineNumberMatrix());
    pageMeta.setLastModified(lastModified);
    pageMeta.setJspTags(parse.getJspTags());
    pageMeta.setCodecName(parse.getDefaultCodecDirectiveValue());
    pageMeta.initCodec();
    // just return groovy and don't compile if asked
    if (isReloadEnabled() || GrailsUtil.isDevelopmentEnv()) {
      pageMeta.setGroovySource(in);
    }

    return pageMeta;
  }
  private GroovyPageTemplate createTemplateFromPrecompiled(String originalUri, String uri) {
    if (precompiledGspMap != null) {
      GroovyPageMetaInfo meta = precompiledCache.get(uri);
      if (meta != null) {
        return new GroovyPageTemplate(meta);
      }
      String gspClassName = precompiledGspMap.get(uri);
      if (gspClassName != null) {
        Class<GroovyPage> gspClass = null;
        try {
          gspClass =
              (Class<GroovyPage>)
                  Class.forName(gspClassName, true, Thread.currentThread().getContextClassLoader());
        } catch (ClassNotFoundException e) {
          LOG.warn(
              "Cannot load class " + gspClassName + ". Resuming on non-precompiled implementation.",
              e);
        }
        if (gspClass != null) {
          meta = new GroovyPageMetaInfo(gspClass);
          meta.setJspTagLibraryResolver(jspTagLibraryResolver);
          meta.setTagLibraryLookup(tagLibraryLookup);
          if (LOG.isDebugEnabled()) {
            LOG.debug(
                "Adding GSP class GroovyPageMetaInfo in cache for uri "
                    + uri
                    + " classname is "
                    + gspClassName);
          }
          precompiledCache.put(uri, meta);
          precompiledCache.put(originalUri, meta);
          return new GroovyPageTemplate(meta);
        }
      }
      if (precompiledGspMap.size() > 0) {}

      if (LOG.isDebugEnabled()) {
        LOG.debug("No precompiled template found for uri '" + uri + "'");
      }
    }
    return null;
  }
 /**
  * Establishes whether a Groovy page is reloadable. A GSP is only reloadable in the development
  * environment.
  *
  * @param resource The Resource to check.
  * @param meta The current GroovyPageMetaInfo instance
  * @return True if it is reloadable
  */
 private boolean isGroovyPageReloadable(Resource resource, GroovyPageMetaInfo meta) {
   return isReloadEnabled() && (establishLastModified(resource) > meta.getLastModified());
 }