/* | |
* 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.struts2.jasper; | |
import com.opensymphony.xwork2.util.finder.ClassLoaderInterface; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import org.apache.struts2.jasper.compiler.Compiler; | |
import org.apache.struts2.jasper.compiler.*; | |
import org.apache.struts2.jasper.servlet.JspCServletContext; | |
import java.io.*; | |
import java.net.URL; | |
import java.net.URLClassLoader; | |
import java.util.*; | |
/** | |
* Shell for the jspc compiler. Handles all options associated with the | |
* command line and creates compilation contexts which it then compiles | |
* according to the specified options. | |
* | |
* This version can process files from a _single_ webapp at once, i.e. | |
* a single docbase can be specified. | |
* | |
* It can be used as an Ant task using: | |
* <pre> | |
* <taskdef classname="org.apache.struts.jasperJspC" name="jasper2" > | |
* <classpath> | |
* <pathelement location="${java.home}/../lib/tools.jar"/> | |
* <fileset dir="${ENV.CATALINA_HOME}/server/lib"> | |
* <include name="*.jar"/> | |
* </fileset> | |
* <fileset dir="${ENV.CATALINA_HOME}/common/lib"> | |
* <include name="*.jar"/> | |
* </fileset> | |
* <path refid="myjars"/> | |
* </classpath> | |
* </taskdef> | |
* | |
* <jasper2 verbose="0" | |
* package="my.package" | |
* uriroot="${webapps.dir}/${webapp.name}" | |
* webXmlFragment="${build.dir}/generated_web.xml" | |
* outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" /> | |
* </pre> | |
* | |
* @author Danno Ferrin | |
* @author Pierre Delisle | |
* @author Costin Manolache | |
* @author Yoav Shapira | |
*/ | |
public class JspC implements Options { | |
/** The default Microsoft Internet Explorer class ID. */ | |
public static final String DEFAULT_IE_CLASS_ID = | |
"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; | |
/** Logger (set by constructor.) */ | |
private Log log; | |
private static final String SWITCH_VERBOSE = "-v"; | |
private static final String SWITCH_HELP = "-help"; | |
private static final String SWITCH_QUIET = "-q"; | |
private static final String SWITCH_OUTPUT_DIR = "-d"; | |
private static final String SWITCH_IE_CLASS_ID = "-ieplugin"; | |
private static final String SWITCH_PACKAGE_NAME = "-p"; | |
private static final String SWITCH_CACHE = "-cache"; | |
private static final String SWITCH_CLASS_NAME = "-c"; | |
private static final String SWITCH_FULL_STOP = "--"; | |
private static final String SWITCH_COMPILE = "-compile"; | |
private static final String SWITCH_SOURCE = "-source"; | |
private static final String SWITCH_TARGET = "-target"; | |
private static final String SWITCH_URI_BASE = "-uribase"; | |
private static final String SWITCH_URI_ROOT = "-uriroot"; | |
private static final String SWITCH_FILE_WEBAPP = "-webapp"; | |
private static final String SWITCH_WEBAPP_INC = "-webinc"; | |
private static final String SWITCH_WEBAPP_XML = "-webxml"; | |
private static final String SWITCH_MAPPED = "-mapped"; | |
private static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; | |
private static final String SWITCH_TRIM_SPACES = "-trimSpaces"; | |
private static final String SWITCH_CLASSPATH = "-classpath"; | |
private static final String SWITCH_DIE = "-die"; | |
private static final String SWITCH_POOLING = "-poolingEnabled"; | |
private static final String SWITCH_ENCODING = "-javaEncoding"; | |
private static final String SWITCH_SMAP = "-smap"; | |
private static final String SWITCH_DUMP_SMAP = "-dumpsmap"; | |
private static final String SHOW_SUCCESS ="-s"; | |
private static final String LIST_ERRORS = "-l"; | |
private static final int NO_WEBXML = 0; | |
private static final int INC_WEBXML = 10; | |
private static final int ALL_WEBXML = 20; | |
private static final int DEFAULT_DIE_LEVEL = 1; | |
private static final int NO_DIE_LEVEL = 0; | |
private static final String[] insertBefore = | |
{ "</web-app>", "<servlet-mapping>", "<session-config>", | |
"<mime-mapping>", "<welcome-file-list>", "<error-page>", "<taglib>", | |
"<resource-env-ref>", "<resource-ref>", "<security-constraint>", | |
"<login-config>", "<security-role>", "<env-entry>", "<ejb-ref>", | |
"<ejb-local-ref>" }; | |
private static int die; | |
private String classPath = null; | |
private URLClassLoader loader = null; | |
private boolean trimSpaces = false; | |
private boolean genStringAsCharArray = false; | |
private boolean xpoweredBy; | |
private boolean mappedFile = false; | |
private boolean poolingEnabled = true; | |
private File scratchDir; | |
private String ieClassId = DEFAULT_IE_CLASS_ID; | |
private String targetPackage; | |
private String targetClassName; | |
private String uriBase; | |
//private String uriRoot; | |
private int dieLevel; | |
private boolean helpNeeded = false; | |
private boolean compile = false; | |
private boolean smapSuppressed = true; | |
private boolean smapDumped = false; | |
private boolean caching = true; | |
private Map cache = new HashMap(); | |
private String compiler = null; | |
private ClassLoaderInterface classLoaderInterface; | |
private String compilerTargetVM = "1.4"; | |
private String compilerSourceVM = "1.4"; | |
private boolean classDebugInfo = true; | |
/** | |
* Throw an exception if there's a compilation error, or swallow it. | |
* Default is true to preserve old behavior. | |
*/ | |
private boolean failOnError = true; | |
/** | |
* The file extensions to be handled as JSP files. | |
* Default list is .jsp and .jspx. | |
*/ | |
private List extensions; | |
/** | |
* The pages. | |
*/ | |
private List pages = new Vector(); | |
/** | |
* Needs better documentation, this data member does. | |
* True by default. | |
*/ | |
private boolean errorOnUseBeanInvalidClassAttribute = true; | |
/** | |
* The java file encoding. Default | |
* is UTF-8. Added per bugzilla 19622. | |
*/ | |
private String javaEncoding = "UTF-8"; | |
// Generation of web.xml fragments | |
private String webxmlFile; | |
private int webxmlLevel; | |
private Writer mapout; | |
private CharArrayWriter servletout; | |
private CharArrayWriter mappingout; | |
/** | |
* The servlet context. | |
*/ | |
private JspCServletContext context; | |
/** | |
* The runtime context. | |
* Maintain a dummy JspRuntimeContext for compiling tag files. | |
*/ | |
private JspRuntimeContext rctxt; | |
/** | |
* Cache for the TLD locations | |
*/ | |
private TldLocationsCache tldLocationsCache = null; | |
private JspConfig jspConfig = null; | |
private TagPluginManager tagPluginManager = null; | |
private boolean verbose = false; | |
private boolean listErrors = false; | |
private boolean showSuccess = false; | |
private int argPos; | |
private boolean fullstop = false; | |
private String args[]; | |
private String sourceCode; | |
public static void main(String arg[]) { | |
if (arg.length == 0) { | |
System.out.println(Localizer.getMessage("jspc.usage")); | |
} else { | |
try { | |
JspC jspc = new JspC(); | |
jspc.setArgs(arg); | |
if (jspc.helpNeeded) { | |
System.out.println(Localizer.getMessage("jspc.usage")); | |
} else { | |
jspc.execute(); | |
} | |
} catch (JasperException je) { | |
System.err.println(je); | |
//System.err.println(je.getMessage()); | |
if (die != NO_DIE_LEVEL) { | |
System.exit(die); | |
} | |
} | |
} | |
} | |
/** Constructor. */ | |
public JspC() { | |
log = LogFactory.getLog(getClass()); | |
} | |
public String getSourceCode() { | |
return sourceCode; | |
} | |
public void setClassLoaderInterface(ClassLoaderInterface classLoaderInterface) { | |
this.classLoaderInterface = classLoaderInterface; | |
} | |
public void setArgs(String[] arg) throws JasperException { | |
args = arg; | |
String tok; | |
dieLevel = NO_DIE_LEVEL; | |
die = dieLevel; | |
while ((tok = nextArg()) != null) { | |
if (tok.equals(SWITCH_VERBOSE)) { | |
verbose = true; | |
showSuccess = true; | |
listErrors = true; | |
} else if (tok.equals(SWITCH_OUTPUT_DIR)) { | |
tok = nextArg(); | |
setOutputDir( tok ); | |
} else if (tok.equals(SWITCH_PACKAGE_NAME)) { | |
targetPackage = nextArg(); | |
} else if (tok.equals(SWITCH_COMPILE)) { | |
compile=true; | |
} else if (tok.equals(SWITCH_CLASS_NAME)) { | |
targetClassName = nextArg(); | |
} else if (tok.equals(SWITCH_URI_BASE)) { | |
uriBase=nextArg(); | |
} else if ( tok.equals( SHOW_SUCCESS ) ) { | |
showSuccess = true; | |
} else if ( tok.equals( LIST_ERRORS ) ) { | |
listErrors = true; | |
} else if (tok.equals(SWITCH_WEBAPP_INC)) { | |
webxmlFile = nextArg(); | |
if (webxmlFile != null) { | |
webxmlLevel = INC_WEBXML; | |
} | |
} else if (tok.equals(SWITCH_WEBAPP_XML)) { | |
webxmlFile = nextArg(); | |
if (webxmlFile != null) { | |
webxmlLevel = ALL_WEBXML; | |
} | |
} else if (tok.equals(SWITCH_MAPPED)) { | |
mappedFile = true; | |
} else if (tok.equals(SWITCH_XPOWERED_BY)) { | |
xpoweredBy = true; | |
} else if (tok.equals(SWITCH_TRIM_SPACES)) { | |
setTrimSpaces(true); | |
} else if (tok.equals(SWITCH_CACHE)) { | |
tok = nextArg(); | |
if ("false".equals(tok)) { | |
caching = false; | |
} else { | |
caching = true; | |
} | |
} else if (tok.equals(SWITCH_CLASSPATH)) { | |
setClassPath(nextArg()); | |
} else if (tok.startsWith(SWITCH_DIE)) { | |
try { | |
dieLevel = Integer.parseInt( | |
tok.substring(SWITCH_DIE.length())); | |
} catch (NumberFormatException nfe) { | |
dieLevel = DEFAULT_DIE_LEVEL; | |
} | |
die = dieLevel; | |
} else if (tok.equals(SWITCH_HELP)) { | |
helpNeeded = true; | |
} else if (tok.equals(SWITCH_POOLING)) { | |
tok = nextArg(); | |
if ("false".equals(tok)) { | |
poolingEnabled = false; | |
} else { | |
poolingEnabled = true; | |
} | |
} else if (tok.equals(SWITCH_ENCODING)) { | |
setJavaEncoding(nextArg()); | |
} else if (tok.equals(SWITCH_SOURCE)) { | |
setCompilerSourceVM(nextArg()); | |
} else if (tok.equals(SWITCH_TARGET)) { | |
setCompilerTargetVM(nextArg()); | |
} else if (tok.equals(SWITCH_SMAP)) { | |
smapSuppressed = false; | |
} else if (tok.equals(SWITCH_DUMP_SMAP)) { | |
smapDumped = true; | |
} else { | |
if (tok.startsWith("-")) { | |
throw new JasperException("Unrecognized option: " + tok + | |
". Use -help for help."); | |
} | |
if (!fullstop) { | |
argPos--; | |
} | |
// Start treating the rest as JSP Pages | |
break; | |
} | |
} | |
// Add all extra arguments to the list of files | |
while( true ) { | |
String file = nextFile(); | |
if( file==null ) { | |
break; | |
} | |
pages.add( file ); | |
} | |
} | |
public boolean getKeepGenerated() { | |
// isn't this why we are running jspc? | |
return true; | |
} | |
public boolean getTrimSpaces() { | |
return trimSpaces; | |
} | |
public void setTrimSpaces(boolean ts) { | |
this.trimSpaces = ts; | |
} | |
public boolean isPoolingEnabled() { | |
return poolingEnabled; | |
} | |
public void setPoolingEnabled(boolean poolingEnabled) { | |
this.poolingEnabled = poolingEnabled; | |
} | |
public boolean isXpoweredBy() { | |
return xpoweredBy; | |
} | |
public void setXpoweredBy(boolean xpoweredBy) { | |
this.xpoweredBy = xpoweredBy; | |
} | |
public boolean getErrorOnUseBeanInvalidClassAttribute() { | |
return errorOnUseBeanInvalidClassAttribute; | |
} | |
public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { | |
errorOnUseBeanInvalidClassAttribute = b; | |
} | |
public int getTagPoolSize() { | |
return Constants.MAX_POOL_SIZE; | |
} | |
/** | |
* Are we supporting HTML mapped servlets? | |
*/ | |
public boolean getMappedFile() { | |
return mappedFile; | |
} | |
// Off-line compiler, no need for security manager | |
public Object getProtectionDomain() { | |
return null; | |
} | |
public boolean getSendErrorToClient() { | |
// implied send to System.err | |
return true; | |
} | |
public void setClassDebugInfo( boolean b ) { | |
classDebugInfo=b; | |
} | |
public boolean getClassDebugInfo() { | |
// compile with debug info | |
return classDebugInfo; | |
} | |
/** | |
* @see Options#isCaching() | |
*/ | |
public boolean isCaching() { | |
return caching; | |
} | |
/** | |
* @see Options#isCaching() | |
*/ | |
public void setCaching(boolean caching) { | |
this.caching = caching; | |
} | |
/** | |
* @see Options#getCache() | |
*/ | |
public Map getCache() { | |
return cache; | |
} | |
/** | |
* Background compilation check intervals in seconds | |
*/ | |
public int getCheckInterval() { | |
return 0; | |
} | |
/** | |
* Modification test interval. | |
*/ | |
public int getModificationTestInterval() { | |
return 0; | |
} | |
/** | |
* Is Jasper being used in development mode? | |
*/ | |
public boolean getDevelopment() { | |
return false; | |
} | |
/** | |
* Is the generation of SMAP info for JSR45 debuggin suppressed? | |
*/ | |
public boolean isSmapSuppressed() { | |
return smapSuppressed; | |
} | |
/** | |
* Set smapSuppressed flag. | |
*/ | |
public void setSmapSuppressed(boolean smapSuppressed) { | |
this.smapSuppressed = smapSuppressed; | |
} | |
/** | |
* Should SMAP info for JSR45 debugging be dumped to a file? | |
*/ | |
public boolean isSmapDumped() { | |
return smapDumped; | |
} | |
/** | |
* Set smapSuppressed flag. | |
*/ | |
public void setSmapDumped(boolean smapDumped) { | |
this.smapDumped = smapDumped; | |
} | |
/** | |
* Determines whether text strings are to be generated as char arrays, | |
* which improves performance in some cases. | |
* | |
* @param genStringAsCharArray true if text strings are to be generated as | |
* char arrays, false otherwise | |
*/ | |
public void setGenStringAsCharArray(boolean genStringAsCharArray) { | |
this.genStringAsCharArray = genStringAsCharArray; | |
} | |
/** | |
* Indicates whether text strings are to be generated as char arrays. | |
* | |
* @return true if text strings are to be generated as char arrays, false | |
* otherwise | |
*/ | |
public boolean genStringAsCharArray() { | |
return genStringAsCharArray; | |
} | |
/** | |
* Sets the class-id value to be sent to Internet Explorer when using | |
* <jsp:plugin> tags. | |
* | |
* @param ieClassId Class-id value | |
*/ | |
public void setIeClassId(String ieClassId) { | |
this.ieClassId = ieClassId; | |
} | |
/** | |
* Gets the class-id value that is sent to Internet Explorer when using | |
* <jsp:plugin> tags. | |
* | |
* @return Class-id value | |
*/ | |
public String getIeClassId() { | |
return ieClassId; | |
} | |
public File getScratchDir() { | |
return scratchDir; | |
} | |
public Class getJspCompilerPlugin() { | |
// we don't compile, so this is meanlingless | |
return null; | |
} | |
public String getJspCompilerPath() { | |
// we don't compile, so this is meanlingless | |
return null; | |
} | |
/** | |
* Compiler to use. | |
*/ | |
public String getCompiler() { | |
return compiler; | |
} | |
public void setCompiler(String c) { | |
compiler=c; | |
} | |
/** | |
* @see Options#getCompilerTargetVM | |
*/ | |
public String getCompilerTargetVM() { | |
return compilerTargetVM; | |
} | |
public void setCompilerTargetVM(String vm) { | |
compilerTargetVM = vm; | |
} | |
/** | |
* @see Options#getCompilerSourceVM() | |
*/ | |
public String getCompilerSourceVM() { | |
return compilerSourceVM; | |
} | |
/** | |
* @see Options#getCompilerSourceVM() | |
*/ | |
public void setCompilerSourceVM(String vm) { | |
compilerSourceVM = vm; | |
} | |
public TldLocationsCache getTldLocationsCache() { | |
return tldLocationsCache; | |
} | |
/** | |
* Returns the encoding to use for | |
* java files. The default is UTF-8. | |
* | |
* @return String The encoding | |
*/ | |
public String getJavaEncoding() { | |
return javaEncoding; | |
} | |
/** | |
* Sets the encoding to use for | |
* java files. | |
* | |
* @param encodingName The name, e.g. "UTF-8" | |
*/ | |
public void setJavaEncoding(String encodingName) { | |
javaEncoding = encodingName; | |
} | |
public boolean getFork() { | |
return false; | |
} | |
public String getClassPath() { | |
if( classPath != null ) | |
return classPath; | |
return System.getProperty("java.class.path"); | |
} | |
public void setClassPath(String s) { | |
classPath=s; | |
} | |
/** | |
* Returns the list of file extensions | |
* that are treated as JSP files. | |
* | |
* @return The list of extensions | |
*/ | |
public List getExtensions() { | |
return extensions; | |
} | |
/** | |
* Adds the given file extension to the | |
* list of extensions handled as JSP files. | |
* | |
* @param extension The extension to add, e.g. "myjsp" | |
*/ | |
protected void addExtension(final String extension) { | |
if(extension != null) { | |
if(extensions == null) { | |
extensions = new Vector(); | |
} | |
extensions.add(extension); | |
} | |
} | |
/** | |
* Parses comma-separated list of JSP files to be processed. If the argument | |
* is null, nothing is done. | |
* | |
* <p>Each file is interpreted relative to uriroot, unless it is absolute, | |
* in which case it must start with uriroot.</p> | |
* | |
* @param jspFiles Comma-separated list of JSP files to be processed | |
*/ | |
public void setJspFiles(final String jspFiles) { | |
if(jspFiles == null) { | |
return; | |
} | |
StringTokenizer tok = new StringTokenizer(jspFiles, ","); | |
while (tok.hasMoreTokens()) { | |
pages.add(tok.nextToken()); | |
} | |
} | |
/** | |
* Sets the compile flag. | |
* | |
* @param b Flag value | |
*/ | |
public void setCompile( final boolean b ) { | |
compile = b; | |
} | |
/** | |
* Sets the verbosity level. The actual number doesn't | |
* matter: if it's greater than zero, the verbose flag will | |
* be true. | |
* | |
* @param level Positive means verbose | |
*/ | |
public void setVerbose( final int level ) { | |
if (level > 0) { | |
verbose = true; | |
showSuccess = true; | |
listErrors = true; | |
} | |
} | |
public void setValidateXml( boolean b ) { | |
org.apache.struts2.jasper.xmlparser.ParserUtils.validating=b; | |
} | |
public void setListErrors( boolean b ) { | |
listErrors = b; | |
} | |
public void setOutputDir( String s ) { | |
if( s!= null ) { | |
scratchDir = resolveFile(s).getAbsoluteFile(); | |
} else { | |
scratchDir=null; | |
} | |
} | |
public void setPackage( String p ) { | |
targetPackage=p; | |
} | |
/** | |
* Class name of the generated file ( without package ). | |
* Can only be used if a single file is converted. | |
* XXX Do we need this feature ? | |
*/ | |
public void setClassName( String p ) { | |
targetClassName=p; | |
} | |
/** | |
* File where we generate a web.xml fragment with the class definitions. | |
*/ | |
public void setWebXmlFragment( String s ) { | |
webxmlFile=resolveFile(s).getAbsolutePath(); | |
webxmlLevel=INC_WEBXML; | |
} | |
/** | |
* File where we generate a complete web.xml with the class definitions. | |
*/ | |
public void setWebXml( String s ) { | |
webxmlFile=resolveFile(s).getAbsolutePath(); | |
webxmlLevel=ALL_WEBXML; | |
} | |
/** | |
* Set the option that throws an exception in case of a compilation error. | |
*/ | |
public void setFailOnError(final boolean b) { | |
failOnError = b; | |
} | |
public boolean getFailOnError() { | |
return failOnError; | |
} | |
/** | |
* Obtain JSP configuration informantion specified in web.xml. | |
*/ | |
public JspConfig getJspConfig() { | |
return jspConfig; | |
} | |
public TagPluginManager getTagPluginManager() { | |
return tagPluginManager; | |
} | |
public void generateWebMapping( String file, JspCompilationContext clctxt ) | |
throws IOException | |
{ | |
if (log.isDebugEnabled()) { | |
log.debug("Generating web mapping for file " + file | |
+ " using compilation context " + clctxt); | |
} | |
String className = clctxt.getServletClassName(); | |
String packageName = clctxt.getServletPackageName(); | |
String thisServletName; | |
if ("".equals(packageName)) { | |
thisServletName = className; | |
} else { | |
thisServletName = packageName + '.' + className; | |
} | |
if (servletout != null) { | |
servletout.write("\n <servlet>\n <servlet-name>"); | |
servletout.write(thisServletName); | |
servletout.write("</servlet-name>\n <servlet-class>"); | |
servletout.write(thisServletName); | |
servletout.write("</servlet-class>\n </servlet>\n"); | |
} | |
if (mappingout != null) { | |
mappingout.write("\n <servlet-mapping>\n <servlet-name>"); | |
mappingout.write(thisServletName); | |
mappingout.write("</servlet-name>\n <url-pattern>"); | |
mappingout.write(file.replace('\\', '/')); | |
mappingout.write("</url-pattern>\n </servlet-mapping>\n"); | |
} | |
} | |
private void processFile(String file) | |
throws JasperException | |
{ | |
if (log.isDebugEnabled()) { | |
log.debug("Processing file: " + file); | |
} | |
ClassLoader originalClassLoader = null; | |
try { | |
// set up a scratch/output dir if none is provided | |
if (scratchDir == null) { | |
String temp = System.getProperty("java.io.tmpdir"); | |
if (temp == null) { | |
temp = ""; | |
} | |
scratchDir = new File(new File(temp).getAbsolutePath()); | |
} | |
String jspUri=file.replace('\\','/'); | |
JspCompilationContext clctxt = new JspCompilationContext | |
( jspUri, false, this, context, null, rctxt, classLoaderInterface ); | |
/* Override the defaults */ | |
if ((targetClassName != null) && (targetClassName.length() > 0)) { | |
clctxt.setServletClassName(targetClassName); | |
targetClassName = null; | |
} | |
if (targetPackage != null) { | |
clctxt.setServletPackageName(targetPackage); | |
} | |
originalClassLoader = Thread.currentThread().getContextClassLoader(); | |
if( loader==null ) { | |
initClassLoader( clctxt ); | |
} | |
Thread.currentThread().setContextClassLoader(loader); | |
clctxt.setClassLoader(loader); | |
clctxt.setClassPath(classPath); | |
Compiler clc = clctxt.createCompiler(); | |
// If compile is set, generate both .java and .class, if | |
// .jsp file is newer than .class file; | |
// Otherwise only generate .java, if .jsp file is newer than | |
// the .java file | |
if( clc.isOutDated(compile) ) { | |
if (log.isDebugEnabled()) { | |
log.debug(jspUri + " is out dated, compiling..."); | |
} | |
clc.compile(compile, true); | |
} | |
// Generate mapping | |
generateWebMapping( file, clctxt ); | |
if ( showSuccess ) { | |
log.info( "Built File: " + file ); | |
} | |
this.sourceCode = clctxt.getSourceCode(); | |
} catch (JasperException je) { | |
Throwable rootCause = je; | |
while (rootCause instanceof JasperException | |
&& ((JasperException) rootCause).getRootCause() != null) { | |
rootCause = ((JasperException) rootCause).getRootCause(); | |
} | |
if (rootCause != je) { | |
log.error(Localizer.getMessage("jspc.error.generalException", | |
file), | |
rootCause); | |
} | |
// Bugzilla 35114. | |
if(getFailOnError()) { | |
throw je; | |
} else { | |
log.error(je.getMessage(), je);; | |
} | |
} catch (Exception e) { | |
if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { | |
log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", | |
e.getMessage())); | |
} | |
throw new JasperException(e); | |
} finally { | |
if(originalClassLoader != null) { | |
Thread.currentThread().setContextClassLoader(originalClassLoader); | |
} | |
} | |
} | |
public Set<String> getTldAbsolutePaths() { | |
return tldLocationsCache.getAbsolutePathsOfLocations(); | |
} | |
/** | |
* Executes the compilation. | |
* | |
* @throws JasperException If an error occurs | |
*/ | |
public void execute() throws JasperException { | |
if(log.isDebugEnabled()) { | |
log.debug("execute() starting for " + pages.size() + " pages."); | |
} | |
try { | |
if( context==null ) { | |
initServletContext(); | |
} | |
initWebXml(); | |
Iterator iter = pages.iterator(); | |
while (iter.hasNext()) { | |
String nextjsp = iter.next().toString(); | |
processFile(nextjsp); | |
} | |
completeWebXml(); | |
}catch (JasperException je) { | |
Throwable rootCause = je; | |
while (rootCause instanceof JasperException | |
&& ((JasperException) rootCause).getRootCause() != null) { | |
rootCause = ((JasperException) rootCause).getRootCause(); | |
} | |
if (rootCause != je) { | |
rootCause.printStackTrace(); | |
} | |
throw je; | |
} finally { | |
if (loader != null) { | |
LogFactory.release(loader); | |
} | |
} | |
} | |
// ==================== Private utility methods ==================== | |
private String nextArg() { | |
if ((argPos >= args.length) | |
|| (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { | |
return null; | |
} else { | |
return args[argPos++]; | |
} | |
} | |
private String nextFile() { | |
if (fullstop) argPos++; | |
if (argPos >= args.length) { | |
return null; | |
} else { | |
return args[argPos++]; | |
} | |
} | |
private void initWebXml() { | |
try { | |
if (webxmlLevel >= INC_WEBXML) { | |
File fmapings = new File(webxmlFile); | |
mapout = new FileWriter(fmapings); | |
servletout = new CharArrayWriter(); | |
mappingout = new CharArrayWriter(); | |
} else { | |
mapout = null; | |
servletout = null; | |
mappingout = null; | |
} | |
if (webxmlLevel >= ALL_WEBXML) { | |
mapout.write(Localizer.getMessage("jspc.webxml.header")); | |
mapout.flush(); | |
} else if ((webxmlLevel>= INC_WEBXML)) { | |
mapout.write(Localizer.getMessage("jspc.webinc.header")); | |
mapout.flush(); | |
} | |
} catch (IOException ioe) { | |
mapout = null; | |
servletout = null; | |
mappingout = null; | |
} | |
} | |
private void completeWebXml() { | |
if (mapout != null) { | |
try { | |
servletout.writeTo(mapout); | |
mappingout.writeTo(mapout); | |
if (webxmlLevel >= ALL_WEBXML) { | |
mapout.write(Localizer.getMessage("jspc.webxml.footer")); | |
} else if ((webxmlLevel >= INC_WEBXML)) { | |
mapout.write(Localizer.getMessage("jspc.webinc.footer")); | |
} | |
mapout.close(); | |
} catch (IOException ioe) { | |
// noting to do if it fails since we are done with it | |
} | |
} | |
} | |
private void initServletContext() { | |
context =new JspCServletContext | |
(new PrintWriter(System.out), | |
classLoaderInterface); | |
tldLocationsCache = new TldLocationsCache(context, true); | |
rctxt = new JspRuntimeContext(context, this); | |
jspConfig = new JspConfig(context); | |
tagPluginManager = new TagPluginManager(context); | |
} | |
/** | |
* Initializes the classloader as/if needed for the given | |
* compilation context. | |
* | |
* @param clctxt The compilation context | |
* @throws IOException If an error occurs | |
*/ | |
private void initClassLoader(JspCompilationContext clctxt) | |
throws IOException { | |
classPath = getClassPath(); | |
ClassLoader jspcLoader = getClass().getClassLoader(); | |
// Turn the classPath into URLs | |
ArrayList urls = new ArrayList(); | |
StringTokenizer tokenizer = new StringTokenizer(classPath, | |
File.pathSeparator); | |
while (tokenizer.hasMoreTokens()) { | |
String path = tokenizer.nextToken(); | |
try { | |
File libFile = new File(path); | |
urls.add(libFile.toURL()); | |
} catch (IOException ioe) { | |
// Failing a toCanonicalPath on a file that | |
// exists() should be a JVM regression test, | |
// therefore we have permission to freak uot | |
throw new RuntimeException(ioe.toString()); | |
} | |
} | |
//TODO: add .tld files to the URLCLassLoader | |
URL urlsA[]=new URL[urls.size()]; | |
urls.toArray(urlsA); | |
loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); | |
} | |
/** | |
* Resolves the relative or absolute pathname correctly | |
* in both Ant and command-line situations. If Ant launched | |
* us, we should use the basedir of the current project | |
* to resolve relative paths. | |
* | |
* See Bugzilla 35571. | |
* | |
* @param s The file | |
* @return The file resolved | |
*/ | |
protected File resolveFile(final String s) { | |
//TODO: what to do with this | |
return new File(s); | |
} | |
} |