@Test public void testBug54240() throws Exception { Tomcat tomcat = getTomcatInstanceTestWebapp(false, true); ServletContext context = ((Context) tomcat.getHost().findChildren()[0]).getServletContext(); TagPluginManager manager = new TagPluginManager(context); Node.Nodes nodes = new Node.Nodes(); Node.CustomTag c = new Node.CustomTag( "test:ATag", "test", "ATag", "http://tomcat.apache.org/jasper", null, null, null, null, null, new TagFileInfo("ATag", "http://tomcat.apache.org/jasper", tagInfo)); c.setTagHandlerClass(TesterTag.class); nodes.add(c); manager.apply(nodes, null, null); Node n = nodes.getNode(0); Assert.assertNotNull(n); Assert.assertTrue(n instanceof Node.CustomTag); Node.CustomTag t = (Node.CustomTag) n; Assert.assertNotNull(t.getAtSTag()); Node.Nodes sTag = c.getAtSTag(); Node scriptlet = sTag.getNode(0); Assert.assertNotNull(scriptlet); Assert.assertTrue(scriptlet instanceof Node.Scriptlet); Node.Scriptlet s = (Node.Scriptlet) scriptlet; Assert.assertEquals("//Just a comment", s.getText()); }
@Override public void visit(NodeCustomTag n) throws JasperException { manager.invokePlugin(n, pageInfo); visitBody(n); }
/** 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()); }
/** * 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; }