/** * Compile the jsp file from the current engine context. As an side- effect, tag files that are * referenced by this page are also compiled. * * @param compileClass If true, generate both .java and .class file If false, generate only .java * file * @param jspcMode true if invoked from JspC, false otherwise */ public void compile(boolean compileClass, boolean jspcMode) throws FileNotFoundException, JasperException, Exception { if (errDispatcher == null) { this.errDispatcher = new ErrorDispatcher(jspcMode); } try { String[] smap = generateJava(); if (compileClass) { generateClass(smap); // Fix for bugzilla 41606 // Set JspServletWrapper.servletClassLastModifiedTime after successful compile String targetFileName = ctxt.getClassFileName(); if (targetFileName != null) { File targetFile = new File(targetFileName); if (targetFile.exists() && jsw != null) { jsw.setServletClassLastModifiedTime(targetFile.lastModified()); } } } } finally { if (tfp != null && ctxt.isPrototypeMode()) { tfp.removeProtoTypeFiles(null); } // Make sure these object which are only used during the // generation and compilation of the JSP page get // dereferenced so that they can be GC'd and reduce the // memory footprint. tfp = null; errDispatcher = null; pageInfo = null; // Only get rid of the pageNodes if in production. // In development mode, they are used for detailed // error messages. // http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 if (!this.options.getDevelopment()) { pageNodes = null; } if (ctxt.getWriter() != null) { ctxt.getWriter().close(); ctxt.setWriter(null); } } }
/** * Determine if a compilation is necessary by checking the time stamp of the JSP page with that of * the corresponding .class or .java file. If the page has dependencies, the check is also * extended to its dependeants, and so on. This method can by overidden by a subclasses of * Compiler. * * @param checkClass If true, check against .class file, if false, check against .java file. */ public boolean isOutDated(boolean checkClass) { String jsp = ctxt.getJspFile(); if (jsw != null && (ctxt.getOptions().getModificationTestInterval() > 0)) { if (jsw.getLastModificationTest() + (ctxt.getOptions().getModificationTestInterval() * 1000) > System.currentTimeMillis()) { return false; } else { jsw.setLastModificationTest(System.currentTimeMillis()); } } long jspRealLastModified = 0; // START PWC 6468930 File targetFile; if (checkClass) { targetFile = new File(ctxt.getClassFileName()); } else { targetFile = new File(ctxt.getServletJavaFileName()); } // Get the target file's last modified time. File.lastModified() // returns 0 if the file does not exist. long targetLastModified = targetFile.lastModified(); // Check cached class file if (checkClass) { JspRuntimeContext rtctxt = ctxt.getRuntimeContext(); String className = ctxt.getFullClassName(); long cachedTime = rtctxt.getBytecodeBirthTime(className); if (cachedTime > targetLastModified) { targetLastModified = cachedTime; } else { // Remove from cache, since the bytecodes from the file is more // current, so that JasperLoader won't load the cached version rtctxt.setBytecode(className, null); } } if (targetLastModified == 0L) return true; // Check if the jsp exists in the filesystem (instead of a jar // or a remote location). If yes, then do a File.lastModified() // to determine its last modified time. This is more performant // (fewer stat calls) than the ctxt.getResource() followed by // openConnection(). However, it only works for file system jsps. // If the file has indeed changed, then need to call URL.OpenConnection() // so that the cache loads the latest jsp file if (jsw != null) { File jspFile = jsw.getJspFile(); if (jspFile != null) { jspRealLastModified = jspFile.lastModified(); } } if (jspRealLastModified == 0 || targetLastModified < jspRealLastModified) { // END PWC 6468930 try { URL jspUrl = ctxt.getResource(jsp); if (jspUrl == null) { ctxt.incrementRemoved(); return false; } URLConnection uc = jspUrl.openConnection(); jspRealLastModified = uc.getLastModified(); uc.getInputStream().close(); } catch (Exception e) { e.printStackTrace(); return true; } // START PWC 6468930 } // END PWC 6468930 /* PWC 6468930 long targetLastModified = 0; File targetFile; if( checkClass ) { targetFile = new File(ctxt.getClassFileName()); } else { targetFile = new File(ctxt.getServletJavaFileName()); } if (!targetFile.exists()) { return true; } targetLastModified = targetFile.lastModified(); */ if (checkClass && jsw != null) { jsw.setServletClassLastModifiedTime(targetLastModified); } if (targetLastModified < jspRealLastModified) { // Remember JSP mod time jspModTime = jspRealLastModified; if (log.isLoggable(Level.FINE)) { log.fine("Compiler: outdated: " + targetFile + " " + targetLastModified); } return true; } // determine if source dependent files (e.g. includes using include // directives) have been changed. if (jsw == null) { return false; } List depends = jsw.getDependants(); if (depends == null) { return false; } Iterator it = depends.iterator(); while (it.hasNext()) { String include = (String) it.next(); try { URL includeUrl = ctxt.getResource(include); if (includeUrl == null) { return true; } URLConnection includeUconn = includeUrl.openConnection(); long includeLastModified = includeUconn.getLastModified(); includeUconn.getInputStream().close(); if (includeLastModified > targetLastModified) { // START GlassFish 750 if (include.endsWith(".tld")) { ctxt.clearTaglibs(); ctxt.clearTagFileJarUrls(); } // END GlassFish 750 return true; } } catch (Exception e) { e.printStackTrace(); return true; } } return false; }
/** Compile the servlet from .java file to .class file */ private void generateClass() throws FileNotFoundException, JasperException, Exception { long t1 = 0; if (log.isLoggable(Level.FINE)) { t1 = System.currentTimeMillis(); } String javaFileName = ctxt.getServletJavaFileName(); String classpath = ctxt.getClassPath(); String sep = System.getProperty("path.separator"); // Initializing classpath ArrayList<File> cpath = new ArrayList<File>(); HashSet<String> paths = new HashSet<String>(); // Process classpath, which includes system classpath from compiler // options, plus the context classpath from the classloader String sysClassPath = options.getSystemClassPath(); if (sysClassPath != null) { StringTokenizer tokenizer = new StringTokenizer(sysClassPath, sep); while (tokenizer.hasMoreElements()) { String path = tokenizer.nextToken(); if (!paths.contains(path) && !systemJarInWebinf(path)) { paths.add(path); cpath.add(new File(path)); } } } if (classpath != null) { StringTokenizer tokenizer = new StringTokenizer(classpath, sep); while (tokenizer.hasMoreElements()) { String path = tokenizer.nextToken(); if (!paths.contains(path) && !systemJarInWebinf(path)) { paths.add(path); cpath.add(new File(path)); } } } if (log.isLoggable(Level.FINE)) { log.fine("Using classpath: " + sysClassPath + sep + classpath); } javaCompiler.setClassPath(cpath); // Set debug info javaCompiler.setDebug(options.getClassDebugInfo()); // Initialize and set java extensions String exts = System.getProperty("java.ext.dirs"); if (exts != null) { javaCompiler.setExtdirs(exts); } if (options.getCompilerTargetVM() != null) { javaCompiler.setTargetVM(options.getCompilerTargetVM()); } if (options.getCompilerSourceVM() != null) { javaCompiler.setSourceVM(options.getCompilerSourceVM()); } // Start java compilation JavacErrorDetail[] javacErrors = javaCompiler.compile(ctxt.getFullClassName(), pageNodes); if (javacErrors != null) { // If there are errors, always generate java files to disk. javaCompiler.doJavaFile(true); log.severe("Error compiling file: " + javaFileName); errDispatcher.javacError(javacErrors); } if (log.isLoggable(Level.FINE)) { long t2 = System.currentTimeMillis(); log.fine("Compiled " + javaFileName + " " + (t2 - t1) + "ms"); } // Save or delete the generated Java files, depending on the // value of "keepgenerated" attribute javaCompiler.doJavaFile(ctxt.keepGenerated()); // JSR45 Support if (!ctxt.isPrototypeMode() && !options.isSmapSuppressed()) { smapUtil.installSmap(); } // START CR 6373479 if (jsw != null && jsw.getServletClassLastModifiedTime() <= 0) { jsw.setServletClassLastModifiedTime(javaCompiler.getClassLastModified()); } // END CR 6373479 if (options.getSaveBytecode()) { javaCompiler.saveClassFile(ctxt.getFullClassName(), ctxt.getClassFileName()); } // On some systems, due to file caching, the time stamp for the updated // JSP file may actually be greater than that of the newly created byte // codes in the cache. In such cases, adjust the cache time stamp to // JSP page time, to avoid unnecessary recompilations. ctxt.getRuntimeContext().adjustBytecodeTime(ctxt.getFullClassName(), jspModTime); }
/** * Determine if a compilation is necessary by checking the time stamp of the JSP page with that of * the corresponding .class or .java file. If the page has dependencies, the check is also * extended to its dependents, and so on. This method can by overridden by a subclasses of * Compiler. * * @param checkClass If true, check against .class file, if false, check against .java file. */ public boolean isOutDated(boolean checkClass) { String jsp = ctxt.getJspFile(); if (jsw != null && (ctxt.getOptions().getModificationTestInterval() > 0)) { if (jsw.getLastModificationTest() + (ctxt.getOptions().getModificationTestInterval() * 1000) > System.currentTimeMillis()) { return false; } jsw.setLastModificationTest(System.currentTimeMillis()); } long jspRealLastModified = 0; try { URL jspUrl = ctxt.getResource(jsp); if (jspUrl == null) { ctxt.incrementRemoved(); return true; } URLConnection uc = jspUrl.openConnection(); if (uc instanceof JarURLConnection) { jspRealLastModified = ((JarURLConnection) uc).getJarEntry().getTime(); } else { jspRealLastModified = uc.getLastModified(); } uc.getInputStream().close(); } catch (Exception e) { if (log.isDebugEnabled()) log.debug("Problem accessing resource. Treat as outdated.", e); return true; } long targetLastModified = 0; File targetFile; if (checkClass) { targetFile = new File(ctxt.getClassFileName()); } else { targetFile = new File(ctxt.getServletJavaFileName()); } if (!targetFile.exists()) { return true; } targetLastModified = targetFile.lastModified(); if (checkClass && jsw != null) { jsw.setServletClassLastModifiedTime(targetLastModified); } if (targetLastModified < jspRealLastModified) { if (log.isDebugEnabled()) { log.debug("Compiler: outdated: " + targetFile + " " + targetLastModified); } return true; } // determine if source dependent files (e.g. includes using include // directives) have been changed. if (jsw == null) { return false; } List<String> depends = jsw.getDependants(); if (depends == null) { return false; } Iterator<String> it = depends.iterator(); while (it.hasNext()) { String include = it.next(); try { URL includeUrl = ctxt.getResource(include); if (includeUrl == null) { return true; } URLConnection iuc = includeUrl.openConnection(); long includeLastModified = 0; if (iuc instanceof JarURLConnection) { includeLastModified = ((JarURLConnection) iuc).getJarEntry().getTime(); } else { includeLastModified = iuc.getLastModified(); } iuc.getInputStream().close(); if (includeLastModified > targetLastModified) { return true; } } catch (Exception e) { if (log.isDebugEnabled()) log.debug("Problem accessing resource. Treat as outdated.", e); return true; } } return false; }