Compilerpublic class Compiler extends Object
Fields Summary |
---|
private static com.sun.org.apache.commons.logging.Log | commonsLog | private static com.sun.org.apache.commons.logging.Log | noOpLog | protected org.apache.jasper.JspCompilationContext | ctxt | private ErrorDispatcher | errDispatcher | private PageInfo | pageInfo | private org.apache.jasper.servlet.JspServletWrapper | jsw | private TagFileProcessor | tfp | private JavaCompiler | javaCompiler | private boolean | jspcMode | private com.sun.org.apache.commons.logging.Log | log | private SmapUtil | smapUtil | private org.apache.jasper.Options | options | private Node.Nodes | pageNodes | private long | jspModTime |
Constructors Summary |
---|
public Compiler(org.apache.jasper.JspCompilationContext ctxt, org.apache.jasper.servlet.JspServletWrapper jsw)
// ------------------------------------------------------------ Constructor
// Compiler for parsing only
this.jsw = jsw;
this.ctxt = ctxt;
this.jspcMode = false;
this.options = ctxt.getOptions();
this.log = commonsLog;
this.smapUtil = new SmapUtil(ctxt);
this.errDispatcher = new ErrorDispatcher(jspcMode);
this.javaCompiler = new AntJavaCompiler();
javaCompiler.init(ctxt, errDispatcher, jspcMode);
| public Compiler(org.apache.jasper.JspCompilationContext ctxt, org.apache.jasper.servlet.JspServletWrapper jsw, boolean jspcMode)
this.jsw = jsw;
this.ctxt = ctxt;
this.jspcMode = jspcMode;
this.options = ctxt.getOptions();
this.log = jspcMode? noOpLog: commonsLog;
this.smapUtil = new SmapUtil(ctxt);
this.errDispatcher = new ErrorDispatcher(jspcMode);
initJavaCompiler();
|
Methods Summary |
---|
public void | compile(boolean compileClass)Compile the jsp file from the current engine context. As an side-
effect, tag files that are referenced by this page are also compiled.
try {
// Create the output directory for the generated files
// Always try and create the directory tree, in case the generated
// directories were deleted after the server was started.
ctxt.getOutputDir();
ctxt.makeOutputDir();
// If errDispatcher is nulled from a previous compilation of the
// same page, instantiate one here.
if (errDispatcher == null) {
errDispatcher = new ErrorDispatcher(jspcMode);
}
generateJava();
if (compileClass) {
generateClass();
}
else {
// If called from jspc to only compile to .java files,
// make sure that .java files are written to disk.
javaCompiler.doJavaFile(ctxt.keepGenerated());
}
} finally {
if (tfp != null) {
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;
if (!jspcMode) {
pageInfo = null;
}
pageNodes = null;
if (ctxt.getWriter() != null) {
ctxt.getWriter().close();
ctxt.setWriter(null);
}
}
| private void | generateClass()Compile the servlet from .java file to .class file
long t1 = 0;
if (log.isDebugEnabled()) {
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)) {
paths.add(path);
cpath.add(new File(path));
}
}
}
StringTokenizer tokenizer = new StringTokenizer(classpath, sep);
while (tokenizer.hasMoreElements()) {
String path = tokenizer.nextToken();
if (! paths.contains(path)) {
paths.add(path);
cpath.add(new File(path));
}
}
if(log.isDebugEnabled()) {
log.debug("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.error("Error compiling file: " + javaFileName);
errDispatcher.javacError(javacErrors);
}
if (log.isDebugEnabled()) {
long t2 = System.currentTimeMillis();
log.debug("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);
| private void | generateJava()Compile the jsp file into equivalent servlet in java source
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();
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()));
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.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(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.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
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());
| private java.lang.Class | getClassFor(java.lang.String className)
Class c = null;
try {
c = Class.forName(className, false, getClass().getClassLoader());
} catch (ClassNotFoundException ex) {
}
return c;
| public org.apache.jasper.JspCompilationContext | getCompilationContext()
return ctxt;
| public ErrorDispatcher | getErrorDispatcher()Gets the error dispatcher.
return errDispatcher;
| public PageInfo | getPageInfo()Gets the info about the page under compilation
return pageInfo;
| private void | initJavaCompiler()Get an instance of JavaCompiler.
If Running with Mustang (JDK1.6), use a Jsr199JavaCompiler that
supports JSR199,
else if eclipse's JDT compiler is avalable, use that.
The default is to use javac from ant.
NOTE: When the appserver can be built with and runs only with JDK1.6,
this should be changed to instantiate Jsr199JavaCompiler with new
operator directly.
Class c = getClassFor("javax.tools.ToolProvider");
if (c != null) {
// JDK1.6
c = getClassFor("org.apache.jasper.compiler.Jsr199JavaCompiler");
if (c != null) {
try {
javaCompiler = (JavaCompiler) c.newInstance();
} catch (Exception ex) {
}
}
}
if (javaCompiler == null) {
c = getClassFor("org.eclipse.jdt.internal.compiler.Compiler");
if (c != null) {
c = getClassFor("org.apache.jasper.compiler.JDTJavaCompiler");
if (c != null) {
try {
javaCompiler = (JavaCompiler) c.newInstance();
} catch (Exception ex) {
}
}
}
}
if (javaCompiler == null) {
javaCompiler = new AntJavaCompiler();
}
javaCompiler.init(ctxt, errDispatcher, jspcMode);
| public boolean | isOutDated()This is a protected method intended to be overridden by
subclasses of Compiler. This is used by the compile method
to do all the compilation.
return isOutDated( true );
| public boolean | isOutDated(boolean checkClass)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.
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.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 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;
| public void | removeGeneratedClassFiles()
try {
String classFileName = ctxt.getClassFileName();
if (classFileName != null) {
File classFile = new File(classFileName);
if( log.isDebugEnabled() )
log.debug( "Deleting " + classFile );
classFile.delete();
}
} catch (Exception e) {
// Remove as much as possible, ignore possible exceptions
}
| public void | removeGeneratedFiles()Remove generated files
try {
String classFileName = ctxt.getClassFileName();
if (classFileName != null) {
File classFile = new File(classFileName);
if( log.isDebugEnabled() )
log.debug( "Deleting " + classFile );
classFile.delete();
}
} catch (Exception e) {
// Remove as much as possible, ignore possible exceptions
}
try {
String javaFileName = ctxt.getServletJavaFileName();
if (javaFileName != null) {
File javaFile = new File(javaFileName);
if( log.isDebugEnabled() )
log.debug( "Deleting " + javaFile );
javaFile.delete();
}
} catch (Exception e) {
// Remove as much as possible, ignore possible exceptions
}
| public void | setPageInfo(PageInfo pageInfo)Sets the info about the page under compilation
this.pageInfo = pageInfo;
|
|