/* * 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(); }
/** 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; }