init
This commit is contained in:
607
java/org/apache/jasper/compiler/Compiler.java
Normal file
607
java/org/apache/jasper/compiler/Compiler.java
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.jasper.compiler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.jasper.JasperException;
|
||||
import org.apache.jasper.JspCompilationContext;
|
||||
import org.apache.jasper.Options;
|
||||
import org.apache.jasper.servlet.JspServletWrapper;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.Jar;
|
||||
import org.apache.tomcat.util.scan.JarFactory;
|
||||
|
||||
/**
|
||||
* Main JSP compiler class. This class uses Ant for compiling.
|
||||
*
|
||||
* @author Anil K. Vijendran
|
||||
* @author Mandar Raje
|
||||
* @author Pierre Delisle
|
||||
* @author Kin-man Chung
|
||||
* @author Remy Maucherat
|
||||
* @author Mark Roth
|
||||
*/
|
||||
public abstract class Compiler {
|
||||
|
||||
private final Log log = LogFactory.getLog(Compiler.class); // must not be static
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
protected JspCompilationContext ctxt;
|
||||
|
||||
protected ErrorDispatcher errDispatcher;
|
||||
|
||||
protected PageInfo pageInfo;
|
||||
|
||||
protected JspServletWrapper jsw;
|
||||
|
||||
protected TagFileProcessor tfp;
|
||||
|
||||
protected Options options;
|
||||
|
||||
protected Node.Nodes pageNodes;
|
||||
|
||||
|
||||
// ------------------------------------------------------------ Constructor
|
||||
|
||||
public void init(JspCompilationContext ctxt, JspServletWrapper jsw) {
|
||||
this.jsw = jsw;
|
||||
this.ctxt = ctxt;
|
||||
this.options = ctxt.getOptions();
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Retrieves the parsed nodes of the JSP page, if they are available. May
|
||||
* return null. Used in development mode for generating detailed error
|
||||
* messages. http://bz.apache.org/bugzilla/show_bug.cgi?id=37062.
|
||||
* </p>
|
||||
* @return the page nodes
|
||||
*/
|
||||
public Node.Nodes getPageNodes() {
|
||||
return this.pageNodes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compile the jsp file into equivalent servlet in .java file
|
||||
*
|
||||
* @return a smap for the current JSP page, if one is generated, null
|
||||
* otherwise
|
||||
* @throws Exception Error generating Java source
|
||||
*/
|
||||
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(), ctxt.isTagFile());
|
||||
|
||||
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();
|
||||
|
||||
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
|
||||
try (ServletWriter writer = setupContextWriter(javaFileName)) {
|
||||
Generator.generate(writer, this, pageNodes);
|
||||
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
|
||||
try (ServletWriter writer = setupContextWriter(javaFileName)) {
|
||||
Generator.generate(writer, this, pageNodes);
|
||||
}
|
||||
|
||||
// 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 (RuntimeException e) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
private ServletWriter setupContextWriter(String javaFileName)
|
||||
throws FileNotFoundException, JasperException {
|
||||
ServletWriter writer;
|
||||
// Setup the ServletWriter
|
||||
String javaEncoding = ctxt.getOptions().getJavaEncoding();
|
||||
OutputStreamWriter osw = null;
|
||||
|
||||
try {
|
||||
osw = new OutputStreamWriter(
|
||||
new FileOutputStream(javaFileName), javaEncoding);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
errDispatcher.jspError("jsp.error.needAlternateJavaEncoding",
|
||||
javaEncoding);
|
||||
}
|
||||
|
||||
writer = new ServletWriter(new PrintWriter(osw));
|
||||
ctxt.setWriter(writer);
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet compilation. This compiles the generated sources into
|
||||
* Servlets.
|
||||
* @param smap The SMAP files for source debugging
|
||||
* @throws FileNotFoundException Source files not found
|
||||
* @throws JasperException Compilation error
|
||||
* @throws Exception Some other error
|
||||
*/
|
||||
protected abstract void generateClass(String[] smap)
|
||||
throws FileNotFoundException, JasperException, Exception;
|
||||
|
||||
/**
|
||||
* Compile the jsp file from the current engine context.
|
||||
* @throws FileNotFoundException Source files not found
|
||||
* @throws JasperException Compilation error
|
||||
* @throws Exception Some other error
|
||||
*/
|
||||
public void compile() throws FileNotFoundException, JasperException,
|
||||
Exception {
|
||||
compile(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws FileNotFoundException Source files not found
|
||||
* @throws JasperException Compilation error
|
||||
* @throws Exception Some other error
|
||||
*/
|
||||
public void compile(boolean compileClass) throws FileNotFoundException,
|
||||
JasperException, Exception {
|
||||
compile(compileClass, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws FileNotFoundException Source files not found
|
||||
* @throws JasperException Compilation error
|
||||
* @throws Exception Some other error
|
||||
*/
|
||||
public void compile(boolean compileClass, boolean jspcMode)
|
||||
throws FileNotFoundException, JasperException, Exception {
|
||||
if (errDispatcher == null) {
|
||||
this.errDispatcher = new ErrorDispatcher(jspcMode);
|
||||
}
|
||||
|
||||
try {
|
||||
final Long jspLastModified = ctxt.getLastModified(ctxt.getJspFile());
|
||||
String[] smap = generateJava();
|
||||
File javaFile = new File(ctxt.getServletJavaFileName());
|
||||
if (!javaFile.setLastModified(jspLastModified.longValue())) {
|
||||
throw new JasperException(Localizer.getMessage("jsp.error.setLastModified", javaFile));
|
||||
}
|
||||
if (compileClass) {
|
||||
generateClass(smap);
|
||||
// Fix for bugzilla 41606
|
||||
// Set JspServletWrapper.servletClassLastModifiedTime after successful compile
|
||||
File targetFile = new File(ctxt.getClassFileName());
|
||||
if (targetFile.exists()) {
|
||||
if (!targetFile.setLastModified(jspLastModified.longValue())) {
|
||||
throw new JasperException(
|
||||
Localizer.getMessage("jsp.error.setLastModified", targetFile));
|
||||
}
|
||||
if (jsw != null) {
|
||||
jsw.setServletClassLastModifiedTime(
|
||||
jspLastModified.longValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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://bz.apache.org/bugzilla/show_bug.cgi?id=37062
|
||||
if (!this.options.getDevelopment()) {
|
||||
pageNodes = null;
|
||||
}
|
||||
|
||||
if (ctxt.getWriter() != null) {
|
||||
ctxt.getWriter().close();
|
||||
ctxt.setWriter(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <code>true</code> if the source generation and compilation
|
||||
* should occur
|
||||
*/
|
||||
public boolean isOutDated() {
|
||||
return isOutDated(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return <code>true</code> if the source generation and compilation
|
||||
* should occur
|
||||
*/
|
||||
public boolean isOutDated(boolean checkClass) {
|
||||
|
||||
if (jsw != null
|
||||
&& (ctxt.getOptions().getModificationTestInterval() > 0)) {
|
||||
|
||||
if (jsw.getLastModificationTest()
|
||||
+ (ctxt.getOptions().getModificationTestInterval() * 1000) > System
|
||||
.currentTimeMillis()) {
|
||||
return false;
|
||||
}
|
||||
jsw.setLastModificationTest(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
// Test the target file first. Unless there is an error checking the
|
||||
// last modified time of the source (unlikely) the target is going to
|
||||
// have to be checked anyway. If the target doesn't exist (likely during
|
||||
// startup) this saves an unnecessary check of the source.
|
||||
File targetFile;
|
||||
if (checkClass) {
|
||||
targetFile = new File(ctxt.getClassFileName());
|
||||
} else {
|
||||
targetFile = new File(ctxt.getServletJavaFileName());
|
||||
}
|
||||
if (!targetFile.exists()) {
|
||||
return true;
|
||||
}
|
||||
long targetLastModified = targetFile.lastModified();
|
||||
if (checkClass && jsw != null) {
|
||||
jsw.setServletClassLastModifiedTime(targetLastModified);
|
||||
}
|
||||
|
||||
Long jspRealLastModified = ctxt.getLastModified(ctxt.getJspFile());
|
||||
if (jspRealLastModified.longValue() < 0) {
|
||||
// Something went wrong - assume modification
|
||||
return true;
|
||||
}
|
||||
|
||||
if (targetLastModified != jspRealLastModified.longValue()) {
|
||||
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;
|
||||
}
|
||||
|
||||
Map<String,Long> depends = jsw.getDependants();
|
||||
if (depends == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Entry<String, Long> include : depends.entrySet()) {
|
||||
try {
|
||||
String key = include.getKey();
|
||||
URL includeUrl;
|
||||
long includeLastModified = 0;
|
||||
if (key.startsWith("jar:jar:")) {
|
||||
// Assume we constructed this correctly
|
||||
int entryStart = key.lastIndexOf("!/");
|
||||
String entry = key.substring(entryStart + 2);
|
||||
try (Jar jar = JarFactory.newInstance(new URL(key.substring(4, entryStart)))) {
|
||||
includeLastModified = jar.getLastModified(entry);
|
||||
}
|
||||
} else {
|
||||
if (key.startsWith("jar:") || key.startsWith("file:")) {
|
||||
includeUrl = new URL(key);
|
||||
} else {
|
||||
includeUrl = ctxt.getResource(include.getKey());
|
||||
}
|
||||
if (includeUrl == null) {
|
||||
return true;
|
||||
}
|
||||
URLConnection iuc = includeUrl.openConnection();
|
||||
if (iuc instanceof JarURLConnection) {
|
||||
includeLastModified =
|
||||
((JarURLConnection) iuc).getJarEntry().getTime();
|
||||
} else {
|
||||
includeLastModified = iuc.getLastModified();
|
||||
}
|
||||
iuc.getInputStream().close();
|
||||
}
|
||||
|
||||
if (includeLastModified != include.getValue().longValue()) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Problem accessing resource. Treat as outdated.",
|
||||
e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the error dispatcher.
|
||||
*/
|
||||
public ErrorDispatcher getErrorDispatcher() {
|
||||
return errDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the info about the page under compilation
|
||||
*/
|
||||
public PageInfo getPageInfo() {
|
||||
return pageInfo;
|
||||
}
|
||||
|
||||
public JspCompilationContext getCompilationContext() {
|
||||
return ctxt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove generated files
|
||||
*/
|
||||
public void removeGeneratedFiles() {
|
||||
removeGeneratedClassFiles();
|
||||
|
||||
try {
|
||||
File javaFile = new File(ctxt.getServletJavaFileName());
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Deleting " + javaFile);
|
||||
if (javaFile.exists()) {
|
||||
if (!javaFile.delete()) {
|
||||
log.warn(Localizer.getMessage(
|
||||
"jsp.warning.compiler.javafile.delete.fail",
|
||||
javaFile.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Remove as much as possible, log possible exceptions
|
||||
log.warn(Localizer.getMessage("jsp.warning.compiler.classfile.delete.fail.unknown"),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeGeneratedClassFiles() {
|
||||
try {
|
||||
File classFile = new File(ctxt.getClassFileName());
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Deleting " + classFile);
|
||||
if (classFile.exists()) {
|
||||
if (!classFile.delete()) {
|
||||
log.warn(Localizer.getMessage(
|
||||
"jsp.warning.compiler.classfile.delete.fail",
|
||||
classFile.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Remove as much as possible, log possible exceptions
|
||||
log.warn(Localizer.getMessage("jsp.warning.compiler.classfile.delete.fail.unknown"),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user