/*
     * Appends the page directive with the given attributes to the XML
     * view.
     *
     * Since the import attribute of the page directive is the only page
     * attribute that is allowed to appear multiple times within the same
     * document, and since XML allows only single-value attributes,
     * the values of multiple import attributes must be combined into one,
     * separated by comma.
     *
     * If the given page directive contains just 'contentType' and/or
     * 'pageEncoding' attributes, we ignore it, as we've already appended
     * a page directive containing just these two attributes.
     */
    private void appendPageDirective(Node.PageDirective n) {
      boolean append = false;
      Attributes attrs = n.getAttributes();
      int len = (attrs == null) ? 0 : attrs.getLength();
      for (int i = 0; i < len; i++) {
        @SuppressWarnings("null") // If attrs==null, len == 0
        String attrName = attrs.getQName(i);
        if (!"pageEncoding".equals(attrName) && !"contentType".equals(attrName)) {
          append = true;
          break;
        }
      }
      if (!append) {
        return;
      }

      buf.append("<").append(n.getQName());
      buf.append("\n");

      // append jsp:id
      buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
      buf.append(jspId++).append("\"\n");

      // append remaining attributes
      for (int i = 0; i < len; i++) {
        @SuppressWarnings("null") // If attrs==null, len == 0
        String attrName = attrs.getQName(i);
        if ("import".equals(attrName)
            || "contentType".equals(attrName)
            || "pageEncoding".equals(attrName)) {
          /*
           * Page directive's 'import' attribute is considered
           * further down, and its 'pageEncoding' and 'contentType'
           * attributes are ignored, since we've already appended
           * a new page directive containing just these two
           * attributes
           */
          continue;
        }
        String value = attrs.getValue(i);
        buf.append("  ").append(attrName).append("=\"");
        buf.append(JspUtil.getExprInXml(value)).append("\"\n");
      }
      if (n.getImports().size() > 0) {
        // Concatenate names of imported classes/packages
        boolean first = true;
        ListIterator<String> iter = n.getImports().listIterator();
        while (iter.hasNext()) {
          if (first) {
            first = false;
            buf.append("  import=\"");
          } else {
            buf.append(",");
          }
          buf.append(JspUtil.getExprInXml(iter.next()));
        }
        buf.append("\"\n");
      }
      buf.append("/>\n");
    }
 @Override
 public void visit(Node.ELExpression n) throws JasperException {
   if (!n.getRoot().isXmlSyntax()) {
     buf.append("<").append(JSP_TEXT_ACTION);
     buf.append(" ");
     buf.append(jspIdPrefix);
     buf.append(":id=\"");
     buf.append(jspId++).append("\">");
   }
   buf.append("${");
   buf.append(JspUtil.escapeXml(n.getText()));
   buf.append("}");
   if (!n.getRoot().isXmlSyntax()) {
     buf.append(JSP_TEXT_ACTION_END);
   }
   buf.append("\n");
 }
    /*
     * Appends the attributes of the given Node to the XML view.
     */
    private void printAttributes(Node n, boolean addDefaultNS) {

      /*
       * Append "xmlns" attributes that represent tag libraries
       */
      Attributes attrs = n.getTaglibAttributes();
      int len = (attrs == null) ? 0 : attrs.getLength();
      for (int i = 0; i < len; i++) {
        @SuppressWarnings("null") // If attrs==null, len == 0
        String name = attrs.getQName(i);
        String value = attrs.getValue(i);
        buf.append("  ").append(name).append("=\"").append(value).append("\"\n");
      }

      /*
       * Append "xmlns" attributes that do not represent tag libraries
       */
      attrs = n.getNonTaglibXmlnsAttributes();
      len = (attrs == null) ? 0 : attrs.getLength();
      boolean defaultNSSeen = false;
      for (int i = 0; i < len; i++) {
        @SuppressWarnings("null") // If attrs==null, len == 0
        String name = attrs.getQName(i);
        String value = attrs.getValue(i);
        buf.append("  ").append(name).append("=\"").append(value).append("\"\n");
        defaultNSSeen |= "xmlns".equals(name);
      }
      if (addDefaultNS && !defaultNSSeen) {
        buf.append("  xmlns=\"\"\n");
      }
      resetDefaultNS = false;

      /*
       * Append all other attributes
       */
      attrs = n.getAttributes();
      len = (attrs == null) ? 0 : attrs.getLength();
      for (int i = 0; i < len; i++) {
        @SuppressWarnings("null") // If attrs==null, len == 0
        String name = attrs.getQName(i);
        String value = attrs.getValue(i);
        buf.append("  ").append(name).append("=\"");
        buf.append(JspUtil.getExprInXml(value)).append("\"\n");
      }
    }
  TagVariableInfo createVariable(TreeNode elem) {
    String nameGiven = null;
    String nameFromAttribute = null;
    String className = "java.lang.String";
    boolean declare = true;
    int scope = VariableInfo.NESTED;

    Iterator list = elem.findChildren();
    while (list.hasNext()) {
      TreeNode element = (TreeNode) list.next();
      String tname = element.getName();
      if ("name-given".equals(tname)) nameGiven = element.getBody();
      else if ("name-from-attribute".equals(tname)) nameFromAttribute = element.getBody();
      else if ("variable-class".equals(tname)) className = element.getBody();
      else if ("declare".equals(tname)) {
        String s = element.getBody();
        if (s != null) declare = JspUtil.booleanValue(s);
      } else if ("scope".equals(tname)) {
        String s = element.getBody();
        if (s != null) {
          if ("NESTED".equals(s)) {
            scope = VariableInfo.NESTED;
          } else if ("AT_BEGIN".equals(s)) {
            scope = VariableInfo.AT_BEGIN;
          } else if ("AT_END".equals(s)) {
            scope = VariableInfo.AT_END;
          }
        }
      } else if ("description".equals(tname)
          || // Ignored elements
          false) {
      } else {
        if (log.isWarnEnabled()) {
          log.warn(Localizer.getMessage("jsp.warning.unknown.element.in.variable", tname));
        }
      }
    }
    return new TagVariableInfo(nameGiven, nameFromAttribute, className, declare, scope);
  }
 public String getTemporaryVariableName() {
   return JspUtil.nextTemporaryVariableName();
 }
Exemple #6
0
  /** Compile the jsp file into equivalent servlet in java source */
  private void generateJava() throws Exception {

    long t1, t2, t3, t4;
    t1 = t2 = t3 = t4 = 0;

    if (log.isLoggable(Level.FINE)) {
      t1 = System.currentTimeMillis();
    }

    // Setup page info area
    pageInfo =
        new PageInfo(new BeanRepository(ctxt.getClassLoader(), errDispatcher), ctxt.getJspFile());

    JspConfig jspConfig = options.getJspConfig();
    JspProperty jspProperty = jspConfig.findJspProperty(ctxt.getJspFile());

    /*
     * If the current uri is matched by a pattern specified in
     * a jsp-property-group in web.xml, initialize pageInfo with
     * those properties.
     */
    pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty.isELIgnored()));
    pageInfo.setScriptingInvalid(JspUtil.booleanValue(jspProperty.isScriptingInvalid()));
    pageInfo.setTrimDirectiveWhitespaces(JspUtil.booleanValue(jspProperty.getTrimSpaces()));
    pageInfo.setDeferredSyntaxAllowedAsLiteral(JspUtil.booleanValue(jspProperty.getPoundAllowed()));
    pageInfo.setErrorOnUndeclaredNamespace(
        JspUtil.booleanValue(jspProperty.errorOnUndeclaredNamespace()));

    if (jspProperty.getIncludePrelude() != null) {
      pageInfo.setIncludePrelude(jspProperty.getIncludePrelude());
    }
    if (jspProperty.getIncludeCoda() != null) {
      pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
    }
    if (options.isDefaultBufferNone() && pageInfo.getBufferValue() == null) {
      // Set to unbuffered if not specified explicitly
      pageInfo.setBuffer(0);
    }

    String javaFileName = ctxt.getServletJavaFileName();
    ServletWriter writer = null;

    try {
      // Setup the ServletWriter
      Writer javaWriter =
          javaCompiler.getJavaWriter(javaFileName, ctxt.getOptions().getJavaEncoding());
      writer = new ServletWriter(new PrintWriter(javaWriter));
      ctxt.setWriter(writer);

      // Reset the temporary variable counter for the generator.
      JspUtil.resetTemporaryVariableName();

      // Parse the file
      ParserController parserCtl = new ParserController(ctxt, this);
      pageNodes = parserCtl.parse(ctxt.getJspFile());

      if (ctxt.isPrototypeMode()) {
        // generate prototype .java file for the tag file
        Generator.generate(writer, this, pageNodes);
        writer.close();
        writer = null;
        return;
      }

      // Validate and process attributes
      Validator.validate(this, pageNodes);

      if (log.isLoggable(Level.FINE)) {
        t2 = System.currentTimeMillis();
      }

      // Collect page info
      Collector.collect(this, pageNodes);

      // Compile (if necessary) and load the tag files referenced in
      // this compilation unit.
      tfp = new TagFileProcessor();
      tfp.loadTagFiles(this, pageNodes);

      if (log.isLoggable(Level.FINE)) {
        t3 = System.currentTimeMillis();
      }

      // Determine which custom tag needs to declare which scripting vars
      ScriptingVariabler.set(pageNodes, errDispatcher);

      // Optimizations by Tag Plugins
      TagPluginManager tagPluginManager = options.getTagPluginManager();
      tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);

      // Optimization: concatenate contiguous template texts.
      TextOptimizer.concatenate(this, pageNodes);

      // Generate static function mapper codes.
      ELFunctionMapper.map(this, pageNodes);

      // generate servlet .java file
      Generator.generate(writer, this, pageNodes);
      writer.close();
      writer = null;

      // The writer is only used during the compile, dereference
      // it in the JspCompilationContext when done to allow it
      // to be GC'd and save memory.
      ctxt.setWriter(null);

      if (log.isLoggable(Level.FINE)) {
        t4 = System.currentTimeMillis();
        log.fine(
            "Generated "
                + javaFileName
                + " total="
                + (t4 - t1)
                + " generate="
                + (t4 - t3)
                + " validate="
                + (t2 - t1));
      }

    } catch (Exception e) {
      if (writer != null) {
        try {
          writer.close();
          writer = null;
        } catch (Exception e1) {
          // do nothing
        }
      }
      // Remove the generated .java file
      javaCompiler.doJavaFile(false);
      throw e;
    } finally {
      if (writer != null) {
        try {
          writer.close();
        } catch (Exception e2) {
          // do nothing
        }
      }
    }

    // JSR45 Support
    if (!options.isSmapSuppressed()) {
      smapUtil.generateSmap(pageNodes);
    }

    // If any proto type .java and .class files was generated,
    // the prototype .java may have been replaced by the current
    // compilation (if the tag file is self referencing), but the
    // .class file need to be removed, to make sure that javac would
    // generate .class again from the new .java file just generated.
    tfp.removeProtoTypeFiles(ctxt.getClassFileName());
  }
  TagAttributeInfo createAttribute(TreeNode elem, String jspVersion) {
    String name = null;
    String type = null;
    String expectedType = null;
    String methodSignature = null;
    boolean required = false,
        rtexprvalue = false,
        reqTime = false,
        isFragment = false,
        deferredValue = false,
        deferredMethod = false;

    Iterator list = elem.findChildren();
    while (list.hasNext()) {
      TreeNode element = (TreeNode) list.next();
      String tname = element.getName();

      if ("name".equals(tname)) {
        name = element.getBody();
      } else if ("required".equals(tname)) {
        String s = element.getBody();
        if (s != null) required = JspUtil.booleanValue(s);
      } else if ("rtexprvalue".equals(tname)) {
        String s = element.getBody();
        if (s != null) rtexprvalue = JspUtil.booleanValue(s);
      } else if ("type".equals(tname)) {
        type = element.getBody();
        if ("1.2".equals(jspVersion)
            && (type.equals("Boolean")
                || type.equals("Byte")
                || type.equals("Character")
                || type.equals("Double")
                || type.equals("Float")
                || type.equals("Integer")
                || type.equals("Long")
                || type.equals("Object")
                || type.equals("Short")
                || type.equals("String"))) {
          type = "java.lang." + type;
        }
      } else if ("fragment".equals(tname)) {
        String s = element.getBody();
        if (s != null) {
          isFragment = JspUtil.booleanValue(s);
        }
      } else if ("deferred-value".equals(tname)) {
        deferredValue = true;
        type = "javax.el.ValueExpression";
        TreeNode child = element.findChild("type");
        if (child != null) {
          expectedType = child.getBody();
          if (expectedType != null) {
            expectedType = expectedType.trim();
          }
        } else {
          expectedType = "java.lang.Object";
        }
      } else if ("deferred-method".equals(tname)) {
        deferredMethod = true;
        type = "javax.el.MethodExpression";
        TreeNode child = element.findChild("method-signature");
        if (child != null) {
          methodSignature = child.getBody();
          if (methodSignature != null) {
            methodSignature = methodSignature.trim();
          }
        } else {
          methodSignature = "java.lang.Object method()";
        }
      } else if ("description".equals(tname)
          || // Ignored elements
          false) {;
      } else {
        if (log.isWarnEnabled()) {
          log.warn(Localizer.getMessage("jsp.warning.unknown.element.in.attribute", tname));
        }
      }
    }

    if (isFragment) {
      /*
       * According to JSP.C-3 ("TLD Schema Element Structure - tag"),
       * 'type' and 'rtexprvalue' must not be specified if 'fragment' has
       * been specified (this will be enforced by validating parser).
       * Also, if 'fragment' is TRUE, 'type' is fixed at
       * javax.servlet.jsp.tagext.JspFragment, and 'rtexprvalue' is fixed
       * at true. See also JSP.8.5.2.
       */
      type = "javax.servlet.jsp.tagext.JspFragment";
      rtexprvalue = true;
    }

    if (!rtexprvalue && type == null) {
      // According to JSP spec, for static values (those determined at
      // translation time) the type is fixed at java.lang.String.
      type = "java.lang.String";
    }

    return new TagAttributeInfo(
        name,
        required,
        type,
        rtexprvalue,
        isFragment,
        null,
        deferredValue,
        deferredMethod,
        expectedType,
        methodSignature);
  }
  private TagInfo createTagInfo(TreeNode elem, String jspVersion) throws JasperException {

    String tagName = null;
    String tagClassName = null;
    String teiClassName = null;

    /*
     * Default body content for JSP 1.2 tag handlers (<body-content> has
     * become mandatory in JSP 2.0, because the default would be invalid for
     * simple tag handlers)
     */
    String bodycontent = "JSP";

    String info = null;
    String displayName = null;
    String smallIcon = null;
    String largeIcon = null;
    boolean dynamicAttributes = false;

    Vector attributeVector = new Vector();
    Vector variableVector = new Vector();
    Iterator list = elem.findChildren();
    while (list.hasNext()) {
      TreeNode element = (TreeNode) list.next();
      String tname = element.getName();

      if ("name".equals(tname)) {
        tagName = element.getBody();
      } else if ("tagclass".equals(tname) || "tag-class".equals(tname)) {
        tagClassName = element.getBody();
      } else if ("teiclass".equals(tname) || "tei-class".equals(tname)) {
        teiClassName = element.getBody();
      } else if ("bodycontent".equals(tname) || "body-content".equals(tname)) {
        bodycontent = element.getBody();
      } else if ("display-name".equals(tname)) {
        displayName = element.getBody();
      } else if ("small-icon".equals(tname)) {
        smallIcon = element.getBody();
      } else if ("large-icon".equals(tname)) {
        largeIcon = element.getBody();
      } else if ("icon".equals(tname)) {
        TreeNode icon = element.findChild("small-icon");
        if (icon != null) {
          smallIcon = icon.getBody();
        }
        icon = element.findChild("large-icon");
        if (icon != null) {
          largeIcon = icon.getBody();
        }
      } else if ("info".equals(tname) || "description".equals(tname)) {
        info = element.getBody();
      } else if ("variable".equals(tname)) {
        variableVector.addElement(createVariable(element));
      } else if ("attribute".equals(tname)) {
        attributeVector.addElement(createAttribute(element, jspVersion));
      } else if ("dynamic-attributes".equals(tname)) {
        dynamicAttributes = JspUtil.booleanValue(element.getBody());
      } else if ("example".equals(tname)) {
        // Ignored elements
      } else if ("tag-extension".equals(tname)) {
        // Ignored
      } else {
        if (log.isWarnEnabled()) {
          log.warn(Localizer.getMessage("jsp.warning.unknown.element.in.tag", tname));
        }
      }
    }

    TagExtraInfo tei = null;
    if (teiClassName != null && !teiClassName.equals("")) {
      try {
        Class teiClass = ctxt.getClassLoader().loadClass(teiClassName);
        tei = (TagExtraInfo) teiClass.newInstance();
      } catch (Exception e) {
        err.jspError("jsp.error.teiclass.instantiation", teiClassName, e);
      }
    }

    TagAttributeInfo[] tagAttributeInfo = new TagAttributeInfo[attributeVector.size()];
    attributeVector.copyInto(tagAttributeInfo);

    TagVariableInfo[] tagVariableInfos = new TagVariableInfo[variableVector.size()];
    variableVector.copyInto(tagVariableInfos);

    TagInfo taginfo =
        new TagInfo(
            tagName,
            tagClassName,
            bodycontent,
            info,
            this,
            tei,
            tagAttributeInfo,
            displayName,
            smallIcon,
            largeIcon,
            tagVariableInfos,
            dynamicAttributes);
    return taginfo;
  }
  /**
   * Compile the jsp file into equivalent servlet in .java file
   *
   * @return a smap for the current JSP page, if one is generated, null otherwise
   */
  protected String[] generateJava() throws Exception {

    String[] smapStr = null;

    long t1, t2, t3, t4;

    t1 = t2 = t3 = t4 = 0;

    if (log.isDebugEnabled()) {
      t1 = System.currentTimeMillis();
    }

    // Setup page info area
    pageInfo =
        new PageInfo(new BeanRepository(ctxt.getClassLoader(), errDispatcher), ctxt.getJspFile());

    JspConfig jspConfig = options.getJspConfig();
    JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(ctxt.getJspFile());

    /*
     * If the current uri is matched by a pattern specified in a
     * jsp-property-group in web.xml, initialize pageInfo with those
     * properties.
     */
    if (jspProperty.isELIgnored() != null) {
      pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty.isELIgnored()));
    }
    if (jspProperty.isScriptingInvalid() != null) {
      pageInfo.setScriptingInvalid(JspUtil.booleanValue(jspProperty.isScriptingInvalid()));
    }
    if (jspProperty.getIncludePrelude() != null) {
      pageInfo.setIncludePrelude(jspProperty.getIncludePrelude());
    }
    if (jspProperty.getIncludeCoda() != null) {
      pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
    }
    if (jspProperty.isDeferedSyntaxAllowedAsLiteral() != null) {
      pageInfo.setDeferredSyntaxAllowedAsLiteral(
          JspUtil.booleanValue(jspProperty.isDeferedSyntaxAllowedAsLiteral()));
    }
    if (jspProperty.isTrimDirectiveWhitespaces() != null) {
      pageInfo.setTrimDirectiveWhitespaces(
          JspUtil.booleanValue(jspProperty.isTrimDirectiveWhitespaces()));
    }
    // Default ContentType processing is deferred until after the page has
    // been parsed
    if (jspProperty.getBuffer() != null) {
      pageInfo.setBufferValue(jspProperty.getBuffer(), null, errDispatcher);
    }
    if (jspProperty.isErrorOnUndeclaredNamespace() != null) {
      pageInfo.setErrorOnUndeclaredNamespace(
          JspUtil.booleanValue(jspProperty.isErrorOnUndeclaredNamespace()));
    }
    if (ctxt.isTagFile()) {
      try {
        double libraryVersion =
            Double.parseDouble(ctxt.getTagInfo().getTagLibrary().getRequiredVersion());
        if (libraryVersion < 2.0) {
          pageInfo.setIsELIgnored("true", null, errDispatcher, true);
        }
        if (libraryVersion < 2.1) {
          pageInfo.setDeferredSyntaxAllowedAsLiteral("true", null, errDispatcher, true);
        }
      } catch (NumberFormatException ex) {
        errDispatcher.jspError(ex);
      }
    }

    ctxt.checkOutputDir();
    String javaFileName = ctxt.getServletJavaFileName();

    ServletWriter writer = null;
    try {
      /*
       * The setting of isELIgnored changes the behaviour of the parser
       * in subtle ways. To add to the 'fun', isELIgnored can be set in
       * any file that forms part of the translation unit so setting it
       * in a file included towards the end of the translation unit can
       * change how the parser should have behaved when parsing content
       * up to the point where isELIgnored was set. Arghh!
       * Previous attempts to hack around this have only provided partial
       * solutions. We now use two passes to parse the translation unit.
       * The first just parses the directives and the second parses the
       * whole translation unit once we know how isELIgnored has been set.
       * TODO There are some possible optimisations of this process.
       */
      // Parse the file
      ParserController parserCtl = new ParserController(ctxt, this);

      // Pass 1 - the directives
      Node.Nodes directives = parserCtl.parseDirectives(ctxt.getJspFile());
      Validator.validateDirectives(this, directives);

      // Pass 2 - the whole translation unit
      pageNodes = parserCtl.parse(ctxt.getJspFile());

      // Leave this until now since it can only be set once - bug 49726
      if (pageInfo.getContentType() == null && jspProperty.getDefaultContentType() != null) {
        pageInfo.setContentType(jspProperty.getDefaultContentType());
      }

      if (ctxt.isPrototypeMode()) {
        // generate prototype .java file for the tag file
        writer = setupContextWriter(javaFileName);
        Generator.generate(writer, this, pageNodes);
        writer.close();
        writer = null;
        return null;
      }

      // Validate and process attributes - don't re-validate the
      // directives we validated in pass 1
      Validator.validateExDirectives(this, pageNodes);

      if (log.isDebugEnabled()) {
        t2 = System.currentTimeMillis();
      }

      // Collect page info
      Collector.collect(this, pageNodes);

      // Compile (if necessary) and load the tag files referenced in
      // this compilation unit.
      tfp = new TagFileProcessor();
      tfp.loadTagFiles(this, pageNodes);

      if (log.isDebugEnabled()) {
        t3 = System.currentTimeMillis();
      }

      // Determine which custom tag needs to declare which scripting vars
      ScriptingVariabler.set(pageNodes, errDispatcher);

      // Optimizations by Tag Plugins
      TagPluginManager tagPluginManager = options.getTagPluginManager();
      tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);

      // Optimization: concatenate contiguous template texts.
      TextOptimizer.concatenate(this, pageNodes);

      // Generate static function mapper codes.
      ELFunctionMapper.map(pageNodes);

      // generate servlet .java file
      writer = setupContextWriter(javaFileName);
      Generator.generate(writer, this, pageNodes);
      writer.close();
      writer = null;

      // The writer is only used during the compile, dereference
      // it in the JspCompilationContext when done to allow it
      // to be GC'd and save memory.
      ctxt.setWriter(null);

      if (log.isDebugEnabled()) {
        t4 = System.currentTimeMillis();
        log.debug(
            "Generated "
                + javaFileName
                + " total="
                + (t4 - t1)
                + " generate="
                + (t4 - t3)
                + " validate="
                + (t2 - t1));
      }

    } catch (Exception e) {
      if (writer != null) {
        try {
          writer.close();
          writer = null;
        } catch (Exception e1) {
          // do nothing
        }
      }
      // Remove the generated .java file
      File file = new File(javaFileName);
      if (file.exists()) {
        if (!file.delete()) {
          log.warn(
              Localizer.getMessage(
                  "jsp.warning.compiler.javafile.delete.fail", file.getAbsolutePath()));
        }
      }
      throw e;
    } finally {
      if (writer != null) {
        try {
          writer.close();
        } catch (Exception e2) {
          // do nothing
        }
      }
    }

    // JSR45 Support
    if (!options.isSmapSuppressed()) {
      smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
    }

    // If any proto type .java and .class files was generated,
    // the prototype .java may have been replaced by the current
    // compilation (if the tag file is self referencing), but the
    // .class file need to be removed, to make sure that javac would
    // generate .class again from the new .java file just generated.
    tfp.removeProtoTypeFiles(ctxt.getClassFileName());

    return smapStr;
  }