/* * 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;
/** * 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.jasper.JspC" name="jasper" > * <classpath> * <pathelement location="${java.home}/../lib/tools.jar"/> * <fileset dir="${ENV.CATALINA_HOME}/lib"> * <include name="*.jar"/> * </fileset> * <path refid="myjars"/> * </classpath> * </taskdef> * * <jasper 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
*/ publicclass JspC extends Task implements Options {
static { // the Validator uses this to access the EL ExpressionFactory
JspFactory.setDefaultFactory(new JspFactoryImpl());
}
/** * Throw an exception if there's a compilation error, or swallow it. * Default is true to preserve old behavior.
*/ protectedboolean failOnError = true;
/** * Should a separate process be forked to perform the compilation?
*/ privateboolean fork = false;
/** * The file extensions to be handled as JSP files. * Default list is .jsp and .jspx.
*/ protected List<String> extensions;
/** * The pages.
*/ protectedfinal List<String> pages = new ArrayList<>();
/** * Needs better documentation, this data member does. * True by default.
*/ protectedboolean errorOnUseBeanInvalidClassAttribute = true;
/** * The java file encoding. Default * is UTF-8. Added per bugzilla 19622.
*/ protected String javaEncoding = "UTF-8";
/** The number of threads to use; default is one per core */ protectedint threadCount = Runtime.getRuntime().availableProcessors();
// Add all extra arguments to the list of files while( true ) {
String file = nextFile(); if( file==null ) { break;
}
pages.add( file );
}
}
/** * In JspC this always returns <code>true</code>. * {@inheritDoc}
*/
@Override publicboolean getKeepGenerated() { // isn't this why we are running jspc? returntrue;
}
@Override public TrimSpacesOption getTrimSpaces() { return trimSpaces;
}
/** * Sets the option to control handling of template text that consists * entirely of whitespace. * * @param ts New value
*/ publicvoid setTrimSpaces(String ts) { this.trimSpaces = TrimSpacesOption.valueOf(ts);
}
/** * Sets the option to enable the tag handler pooling. * @param poolingEnabled New value
*/ publicvoid setPoolingEnabled(boolean poolingEnabled) { this.poolingEnabled = poolingEnabled;
}
/** * Sets the option to issue a compilation error if the class attribute * specified in useBean action is invalid. * @param b New value
*/ publicvoid setErrorOnUseBeanInvalidClassAttribute(boolean b) {
errorOnUseBeanInvalidClassAttribute = b;
}
publicvoid setMappedFile(boolean b) {
mappedFile = b;
}
/** * Sets the option to include debug information in compiled class. * @param b New value
*/ publicvoid setClassDebugInfo( boolean b ) {
classDebugInfo=b;
}
@Override publicboolean getClassDebugInfo() { // compile with debug info return classDebugInfo;
}
/** * 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
*/ publicvoid setGenStringAsCharArray(boolean genStringAsCharArray) { this.genStringAsCharArray = genStringAsCharArray;
}
@Override public File getScratchDir() { return scratchDir;
}
@Override public String getCompiler() { return compiler;
}
/** * Sets the option to determine what compiler to use. * @param c New value * * @see Options#getCompiler()
*/ publicvoid setCompiler(String c) {
compiler=c;
}
@Override public String getCompilerClassName() { returnnull;
}
@Override public String getCompilerTargetVM() { return compilerTargetVM;
}
/** * Sets the compiler target VM. * @param vm New value * * @see Options#getCompilerTargetVM()
*/ publicvoid setCompilerTargetVM(String vm) {
compilerTargetVM = vm;
}
@Override public String getCompilerSourceVM() { return compilerSourceVM;
}
/** * Sets the compiler source VM. * @param vm New value * * @see Options#getCompilerSourceVM()
*/ publicvoid setCompilerSourceVM(String vm) {
compilerSourceVM = vm;
}
@Override public TldCache getTldCache() { return tldCache;
}
/** * Returns the encoding to use for * java files. The default is UTF-8. * * @return String The encoding
*/
@Override public String getJavaEncoding() { return javaEncoding;
}
/** * Sets the encoding to use for * java files. * * @param encodingName The name, e.g. "UTF-8"
*/ publicvoid setJavaEncoding(String encodingName) {
javaEncoding = encodingName;
}
/** * Sets the classpath used while compiling the servlets generated from JSP * files * @param s New value
*/ publicvoid setClassPath(String s) {
classPath=s;
}
/** * Returns the list of file extensions * that are treated as JSP files. * * @return The list of extensions
*/ public List<String> 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"
*/ protectedvoid addExtension(final String extension) { if(extension != null) { if(extensions == null) {
extensions = new ArrayList<>();
}
extensions.add(extension);
}
}
/** * Base dir for the webapp. Used to generate class names and resolve * includes. * @param s New value
*/ publicvoid setUriroot( String s ) { if (s == null) {
uriRoot = null; return;
} try {
uriRoot = resolveFile(s).getCanonicalPath();
} catch( Exception ex ) {
uriRoot = s;
}
}
/** * 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
*/ publicvoid 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
*/ publicvoid setCompile( finalboolean 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
*/ publicvoid setVerbose( finalint level ) { if (level > 0) {
verbose = true;
showSuccess = true;
listErrors = true;
}
}
publicvoid setValidateTld( boolean b ) { this.validateTld = b;
}
/** * Sets the package name to be used for the generated servlet classes. * @param p New value
*/ publicvoid 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 ? * @param p New value
*/ publicvoid setClassName( String p ) {
targetClassName=p;
}
/** * File where we generate configuration with the class definitions to be * included in a web.xml file. * @param s New value
*/ publicvoid setWebXmlInclude( String s ) {
webxmlFile=resolveFile(s).getAbsolutePath();
webxmlLevel=INC_WEBXML;
}
/** * File where we generate a complete web-fragment.xml with the class * definitions. * @param s New value
*/ publicvoid setWebFragmentXml( String s ) {
webxmlFile=resolveFile(s).getAbsolutePath();
webxmlLevel=FRG_WEBXML;
}
/** * File where we generate a complete web.xml with the class definitions. * @param s New value
*/ publicvoid setWebXml( String s ) {
webxmlFile=resolveFile(s).getAbsolutePath();
webxmlLevel=ALL_WEBXML;
}
/** * Sets the encoding to be used to read and write web.xml files. * * <p> * If not specified, defaults to UTF-8. * </p> * * @param encoding * Encoding, e.g. "UTF-8".
*/ publicvoid setWebXmlEncoding(String encoding) {
webxmlEncoding = encoding;
}
/** * Sets the option to merge generated web.xml fragment into the * WEB-INF/web.xml file of the web application that we were processing. * * @param b * <code>true</code> to merge the fragment into the existing * web.xml file of the processed web application * ({uriroot}/WEB-INF/web.xml), <code>false</code> to keep the * generated web.xml fragment
*/ publicvoid setAddWebXmlMappings(boolean b) {
addWebXmlMappings = b;
}
/** * Sets the option that throws an exception in case of a compilation error. * @param b New value
*/ publicvoid setFailOnError(finalboolean b) {
failOnError = b;
}
/** * @return <code>true</code> if an exception will be thrown * in case of a compilation error.
*/ publicboolean getFailOnError() { return failOnError;
}
@Override public JspConfig getJspConfig() { return jspConfig;
}
@Override public TagPluginManager getTagPluginManager() { return tagPluginManager;
}
/** * {@inheritDoc} * <p> * Hard-coded to {@code false} for pre-compiled code to enable repeatable * builds.
*/
@Override publicboolean getGeneratedJavaAddTimestamp() { returnfalse;
}
/** * Adds servlet declaration and mapping for the JSP page servlet to the * generated web.xml fragment. * * @param file * Context-relative path to the JSP file, e.g. * <code>/index.jsp</code> * @param clctxt * Compilation context of the servlet * @throws IOException An IO error occurred
*/ publicvoid generateWebMapping( String file, JspCompilationContext clctxt ) throws IOException
{ if (log.isDebugEnabled()) {
log.debug("Generating web mapping for file " + file
+ " using compilation context " + clctxt);
}
if (!(new File(webxmlFile)).delete() && log.isDebugEnabled()) {
log.debug(Localizer.getMessage("jspc.delete.fail", webxmlFile));
}
}
/* * Assumes valid xml
*/ private String getElement(Reader reader) throws IOException {
StringBuilder result = new StringBuilder();
result.append('<');
boolean done = false;
while (!done) { int current = reader.read(); while (current != '>') { if (current < 0) { thrownew EOFException();
}
result.append((char) current);
current = reader.read();
}
result.append((char) current);
int len = result.length(); if (len > 4 && result.substring(0, 4).equals("")) {
done = true;
}
} else {
done = true;
}
}
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(temp).getAbsoluteFile();
}
// 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...");
}
/** * Locate all jsp files in the webapp. Used if no explicit jsps are * specified. Scan is performed via the ServletContext and will include any * JSPs located in resource JARs.
*/ publicvoid scanFiles() { // Make sure default extensions are always included if ((getExtensions() == null) || (getExtensions().size() < 2)) {
addExtension("jsp");
addExtension("jspx");
}
try { if (uriRoot == null) { if (pages.size() == 0) { thrownew JasperException(Localizer.getMessage("jsp.error.jspc.missingTarget"));
}
String firstJsp = pages.get(0);
File firstJspF = new File(firstJsp); if (!firstJspF.exists()) { thrownew JasperException(Localizer.getMessage( "jspc.error.fileDoesNotExist", firstJsp));
}
locateUriRoot(firstJspF);
}
if (uriRoot == null) { thrownew JasperException(Localizer.getMessage("jsp.error.jspc.no_uriroot"));
}
File uriRootF = new File(uriRoot); if (!uriRootF.isDirectory()) { thrownew JasperException(Localizer.getMessage("jsp.error.jspc.uriroot_not_dir"));
}
if (loader == null) {
loader = initClassLoader();
} if (context == null) {
initServletContext(loader);
}
// No explicit pages, we'll process all .jsp in the webapp if (pages.size() == 0) {
scanFiles();
} else { // Ensure pages are all relative to the uriRoot. // Those that are not will trigger an error later. The error // could be detected earlier but isn't to support the use case // when failFast is not used. for (int i = 0; i < pages.size(); i++) {
String nextjsp = pages.get(i);
File fjsp = new File(nextjsp); if (!fjsp.isAbsolute()) {
fjsp = new File(uriRootF, nextjsp);
} if (!fjsp.exists()) { if (log.isWarnEnabled()) {
log.warn(Localizer.getMessage( "jspc.error.fileDoesNotExist", fjsp.toString()));
} continue;
}
String s = fjsp.getAbsolutePath(); if (s.startsWith(uriRoot)) {
nextjsp = s.substring(uriRoot.length());
} if (nextjsp.startsWith("." + File.separatorChar)) {
nextjsp = nextjsp.substring(2);
}
pages.set(i, nextjsp);
}
}
initWebXml();
int errorCount = 0; long start = System.currentTimeMillis();
ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
ExecutorCompletionService<Void> service = new ExecutorCompletionService<>(threadPool); try { int pageCount = pages.size(); for (String nextjsp : pages) {
service.submit(new ProcessFile(nextjsp));
}
JasperException reportableError = null; for (int i = 0; i < pageCount; i++) { try {
service.take().get();
} catch (ExecutionException e) { if (failFast) { // Generation is not interruptible so any tasks that // have started will complete.
List<Runnable> notExecuted = threadPool.shutdownNow();
i += notExecuted.size();
Throwable t = e.getCause(); if (t instanceof JasperException) {
reportableError = (JasperException) t;
} else {
reportableError = new JasperException(t);
}
} else {
errorCount++;
log.error(Localizer.getMessage("jspc.error.compilation"), e);
}
} catch (InterruptedException e) { // Ignore
}
} if (reportableError != null) { throw reportableError;
}
} finally {
threadPool.shutdown();
}
long time = System.currentTimeMillis() - start;
String msg = Localizer.getMessage("jspc.generation.result",
Integer.toString(errorCount), Long.toString(time)); if (failOnError && errorCount > 0) {
System.out.println(Localizer.getMessage( "jspc.errorCount", Integer.valueOf(errorCount))); thrownew BuildException(msg);
} else {
log.info(msg);
}
protectedvoid initServletContext(ClassLoader classLoader) throws IOException, JasperException { // TODO: should we use the Ant Project's log?
PrintWriter log = new PrintWriter(System.out);
URL resourceBase = new File(uriRoot).getCanonicalFile().toURI().toURL();
context = new JspCServletContext(log, resourceBase, classLoader,
isValidateXml(), isBlockExternal()); if (isValidateTld()) {
context.setInitParameter(Constants.XML_VALIDATION_TLD_INIT_PARAM, "true");
}
initTldScanner(context, classLoader);
try {
scanner.scan();
} catch (SAXException e) { thrownew JasperException(e);
}
tldCache = new TldCache(context, scanner.getUriTldResourcePathMap(),
scanner.getTldResourcePathTaglibXmlMap());
context.setAttribute(TldCache.SERVLET_CONTEXT_ATTRIBUTE_NAME, tldCache);
rctxt = new JspRuntimeContext(context, this);
jspConfig = new JspConfig(context);
tagPluginManager = new TagPluginManager(context);
}
/** * Initializes the classloader as/if needed for the given * compilation context. * @return the classloader that will be used * @throws IOException If an error occurs
*/ protected ClassLoader initClassLoader() throws IOException {
// Turn the classPath into URLs
List<URL> 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.toURI().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 thrownew RuntimeException(ioe.toString());
}
}
File webappBase = new File(uriRoot); if (webappBase.exists()) {
File classes = new File(webappBase, "/WEB-INF/classes"); try { if (classes.exists()) {
classPath = classPath + File.pathSeparator
+ classes.getCanonicalPath();
urls.add(classes.getCanonicalFile().toURI().toURL());
}
} catch (IOException ioe) { // failing a toCanonicalPath on a file that // exists() should be a JVM regression test, // therefore we have permission to freak out thrownew RuntimeException(ioe.toString());
}
File webinfLib = new File(webappBase, "/WEB-INF/lib"); if (webinfLib.exists() && webinfLib.isDirectory()) {
String[] libs = webinfLib.list(); if (libs != null) { for (String lib : libs) { if (lib.length() < 5) { continue;
}
String ext = lib.substring(lib.length() - 4); if (!".jar".equalsIgnoreCase(ext)) { if (".tld".equalsIgnoreCase(ext)) {
log.warn(Localizer.getMessage("jspc.warning.tldInWebInfLib"));
} continue;
} try {
File libFile = new File(webinfLib, lib);
classPath = classPath + File.pathSeparator + libFile.getAbsolutePath();
urls.add(libFile.getAbsoluteFile().toURI().toURL());
} catch (IOException ioe) { // failing a toCanonicalPath on a file that // exists() should be a JVM regression test, // therefore we have permission to freak out thrownew RuntimeException(ioe.toString());
}
}
}
}
}
/** * Find the WEB-INF dir by looking up in the directory tree. * This is used if no explicit docbase is set, but only files. * * @param f The path from which it will start looking
*/ protectedvoid locateUriRoot( File f ) {
String tUriBase = uriBase; if (tUriBase == null) {
tUriBase = "/";
} try { if (f.exists()) {
f = new File(f.getAbsolutePath()); while (true) {
File g = new File(f, "WEB-INF"); if (g.exists() && g.isDirectory()) {
uriRoot = f.getCanonicalPath();
uriBase = tUriBase; if (log.isInfoEnabled()) {
log.info(Localizer.getMessage( "jspc.implicit.uriRoot",
uriRoot));
} break;
} if (f.exists() && f.isDirectory()) {
tUriBase = "/" + f.getName() + "/" + tUriBase;
}
String fParent = f.getParent(); if (fParent == null) { break;
} else {
f = new File(fParent);
}
// If there is no acceptable candidate, uriRoot will // remain null.
}
if (uriRoot != null) {
File froot = new File(uriRoot);
uriRoot = froot.getCanonicalPath();
}
}
} catch (IOException ioe) { // Missing uriRoot will be handled in the caller.
}
}
/** * 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) { if(getProject() == null) { // Note FileUtils.getFileUtils replaces FileUtils.newFileUtils in Ant 1.6.3 return FileUtils.getFileUtils().resolveFile(null, s);
} else { return FileUtils.getFileUtils().resolveFile(getProject().getBaseDir(), s);
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.41Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.