| /* |
| * 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.tools.ant.taskdefs.optional.jsp; |
| |
| import java.io.File; |
| import java.util.Date; |
| import java.util.Enumeration; |
| import java.util.Vector; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.DirectoryScanner; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.taskdefs.MatchingTask; |
| import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapter; |
| import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapterFactory; |
| import org.apache.tools.ant.types.Path; |
| import org.apache.tools.ant.types.Reference; |
| |
| /** |
| * Runs a JSP compiler. |
| * |
| * <p> This task takes the given jsp files and compiles them into java |
| * files. It is then up to the user to compile the java files into classes. |
| * |
| * <p> The task requires the srcdir and destdir attributes to be |
| * set. This Task is a MatchingTask, so the files to be compiled can be |
| * specified using includes/excludes attributes or nested include/exclude |
| * elements. Optional attributes are verbose (set the verbosity level passed |
| * to jasper), package (name of the destination package for generated java |
| * classes and classpath (the classpath to use when running the jsp |
| * compiler). |
| * <p> This task supports the nested elements classpath (A Path) and |
| * classpathref (A Reference) which can be used in preference to the |
| * attribute classpath, if the jsp compiler is not already in the ant |
| * classpath. |
| * |
| * <p><h4>Usage</h4> |
| * <pre> |
| * <jspc srcdir="${basedir}/src/war" |
| * destdir="${basedir}/gensrc" |
| * package="com.i3sp.jsp" |
| * verbose="9"> |
| * <include name="**\/*.jsp" /> |
| * </jspc> |
| * </pre> |
| * |
| * <p> Large Amount of cutting and pasting from the Javac task... |
| * @since 1.5 |
| */ |
| public class JspC extends MatchingTask { |
| private Path classpath; |
| private Path compilerClasspath; |
| private Path src; |
| private File destDir; |
| private String packageName; |
| /** name of the compiler to use */ |
| private String compilerName = "jasper"; |
| |
| /** |
| * -ieplugin <clsid> Java Plugin classid for Internet Explorer |
| */ |
| private String iepluginid; |
| private boolean mapped; |
| private int verbose = 0; |
| // CheckStyle:VisibilityModifier OFF - bc |
| protected Vector compileList = new Vector(); |
| Vector javaFiles = new Vector(); |
| |
| /** |
| * flag to control action on execution trouble |
| */ |
| protected boolean failOnError = true; |
| |
| /** |
| * -uriroot <dir> The root directory that uri files should be resolved |
| * against, |
| */ |
| private File uriroot; |
| |
| /** |
| * -webinc <file> Creates partial servlet mappings for the -webapp option |
| */ |
| private File webinc; |
| |
| /** |
| * -webxml <file> Creates a complete web.xml when using the -webapp option. |
| */ |
| |
| private File webxml; |
| |
| /** |
| * web apps |
| */ |
| protected WebAppParameter webApp; |
| |
| |
| |
| private static final String FAIL_MSG |
| = "Compile failed, messages should have been provided."; |
| |
| // CheckStyle:VisibilityModifier ON |
| |
| /** |
| * Set the path for source JSP files. |
| * @param srcDir the source path. |
| */ |
| public void setSrcDir(Path srcDir) { |
| if (src == null) { |
| src = srcDir; |
| } else { |
| src.append(srcDir); |
| } |
| } |
| |
| /** |
| * Get the source dir. |
| * @return the source path. |
| */ |
| public Path getSrcDir() { |
| return src; |
| } |
| |
| /** |
| * Set the destination directory into which the JSP source |
| * files should be compiled. |
| * @param destDir the destination directory. |
| */ |
| public void setDestdir(File destDir) { |
| this.destDir = destDir; |
| } |
| |
| /** |
| * Get the destination directory. |
| * @return the directory. |
| */ |
| public File getDestdir() { |
| return destDir; |
| } |
| |
| /** |
| * Set the name of the package the compiled jsp files should be in. |
| * @param pkg the name of the package. |
| */ |
| public void setPackage(String pkg) { |
| this.packageName = pkg; |
| } |
| |
| /** |
| * Get the name of the package. |
| * @return the package. |
| */ |
| public String getPackage() { |
| return packageName; |
| } |
| |
| /** |
| * Set the verbose level of the compiler |
| * @param i the verbose level to use. |
| */ |
| public void setVerbose(int i) { |
| verbose = i; |
| } |
| |
| /** |
| * Get the verbose level. |
| * @return the level. |
| */ |
| public int getVerbose() { |
| return verbose; |
| } |
| |
| /** |
| * Whether or not the build should halt if compilation fails. |
| * Defaults to <code>true</code>. |
| * @param fail a <code>boolean</code> value. |
| */ |
| public void setFailonerror(boolean fail) { |
| failOnError = fail; |
| } |
| /** |
| * Gets the failonerror flag. |
| * @return the flag. |
| */ |
| public boolean getFailonerror() { |
| return failOnError; |
| } |
| |
| /** |
| * Get the IE CLASSID value. |
| * @return the value. |
| */ |
| public String getIeplugin() { |
| return iepluginid; |
| } |
| /** |
| * Java Plugin CLASSID for Internet Explorer |
| * @param iepluginid the id to use. |
| */ |
| public void setIeplugin(String iepluginid) { |
| this.iepluginid = iepluginid; |
| } |
| |
| /** |
| * If true, generate separate write() calls for each HTML line |
| * in the JSP. |
| * @return mapping status |
| */ |
| public boolean isMapped() { |
| return mapped; |
| } |
| |
| /** |
| * If true, generate separate write() calls for each HTML line |
| * in the JSP. |
| * @param mapped a <code>boolean</code> value. |
| */ |
| public void setMapped(boolean mapped) { |
| this.mapped = mapped; |
| } |
| |
| /** |
| * The URI context of relative URI references in the JSP pages. |
| * If it does not exist then it is derived from the location |
| * of the file relative to the declared or derived value of uriroot. |
| * |
| * @param uribase The new Uribase value |
| */ |
| public void setUribase(File uribase) { |
| log("Uribase is currently an unused parameter", Project.MSG_WARN); |
| } |
| |
| /** |
| * Get the uri base value. |
| * @return the value. |
| */ |
| public File getUribase() { |
| return uriroot; |
| } |
| |
| /** |
| * The root directory that uri files should be resolved |
| * against. (Default is the directory jspc is invoked from) |
| * |
| * @param uriroot The new Uribase value |
| */ |
| public void setUriroot(File uriroot) { |
| this.uriroot = uriroot; |
| } |
| |
| /** |
| * Get the uri root value. |
| * @return the value. |
| */ |
| public File getUriroot() { |
| return uriroot; |
| } |
| |
| |
| /** |
| * Set the classpath to be used for this compilation. |
| * @param cp the path to be used. |
| */ |
| public void setClasspath(Path cp) { |
| if (classpath == null) { |
| classpath = cp; |
| } else { |
| classpath.append(cp); |
| } |
| } |
| |
| /** |
| * Adds a path to the classpath. |
| * @return a path to be configured. |
| */ |
| public Path createClasspath() { |
| if (classpath == null) { |
| classpath = new Path(getProject()); |
| } |
| return classpath.createPath(); |
| } |
| |
| /** |
| * Adds a reference to a classpath defined elsewhere |
| * @param r a reference to a classpath. |
| */ |
| public void setClasspathRef(Reference r) { |
| createClasspath().setRefid(r); |
| } |
| |
| /** |
| * Get the classpath. |
| * @return the classpath. |
| */ |
| public Path getClasspath() { |
| return classpath; |
| } |
| |
| /** |
| * Set the classpath to be used to find this compiler adapter |
| * @param cp the compiler classpath. |
| */ |
| public void setCompilerclasspath(Path cp) { |
| if (compilerClasspath == null) { |
| compilerClasspath = cp; |
| } else { |
| compilerClasspath.append(cp); |
| } |
| } |
| |
| /** |
| * get the classpath used to find the compiler adapter |
| * @return the compiler classpath. |
| */ |
| public Path getCompilerclasspath() { |
| return compilerClasspath; |
| } |
| |
| /** |
| * Support nested compiler classpath, used to locate compiler adapter |
| * @return a path to be configured. |
| */ |
| public Path createCompilerclasspath() { |
| if (compilerClasspath == null) { |
| compilerClasspath = new Path(getProject()); |
| } |
| return compilerClasspath.createPath(); |
| } |
| |
| /** |
| * Filename for web.xml. |
| * |
| * @param webxml The new Webxml value |
| */ |
| public void setWebxml(File webxml) { |
| this.webxml = webxml; |
| } |
| |
| /** |
| * Filename for web.xml. |
| * @return The filename for web.xml. |
| */ |
| public File getWebxml() { |
| return this.webxml; |
| } |
| |
| /** |
| * output filename for the fraction of web.xml that lists |
| * servlets. |
| * @param webinc The new Webinc value |
| */ |
| public void setWebinc(File webinc) { |
| this.webinc = webinc; |
| } |
| |
| /** |
| * Get the webinc attribute. |
| * @return the webinc attribute. |
| */ |
| public File getWebinc() { |
| return this.webinc; |
| } |
| |
| /** |
| * Adds a single webapp. |
| * |
| * @param webappParam add a web app parameter |
| * @throws BuildException if more than one webapp is specified. |
| */ |
| public void addWebApp(WebAppParameter webappParam) |
| throws BuildException { |
| //demand create vector of filesets |
| if (webApp == null) { |
| webApp = webappParam; |
| } else { |
| throw new BuildException("Only one webapp can be specified"); |
| } |
| } |
| |
| /** |
| * Get the web app. |
| * @return the web app attribute. |
| */ |
| public WebAppParameter getWebApp() { |
| return webApp; |
| } |
| |
| /** |
| * Class name of a JSP compiler adapter. |
| * @param compiler the compiler class name. |
| */ |
| public void setCompiler(String compiler) { |
| this.compilerName = compiler; |
| } |
| |
| /** |
| * get the list of files to compile |
| * @return the list of files. |
| */ |
| public Vector getCompileList() { |
| return compileList; |
| } |
| |
| /** |
| * execute by building up a list of files that |
| * have changed and hand them off to a jsp compiler |
| * @throws BuildException on error. |
| */ |
| public void execute() |
| throws BuildException { |
| |
| // make sure that we've got a destdir |
| if (destDir == null) { |
| throw new BuildException("destdir attribute must be set!", |
| getLocation()); |
| } |
| |
| if (!destDir.isDirectory()) { |
| throw new BuildException("destination directory \"" + destDir |
| + "\" does not exist or is not a directory", getLocation()); |
| } |
| |
| File dest = getActualDestDir(); |
| |
| //bind to a compiler |
| JspCompilerAdapter compiler = |
| JspCompilerAdapterFactory.getCompiler(compilerName, this, |
| getProject().createClassLoader(compilerClasspath)); |
| |
| //if we are a webapp, hand off to the compiler, which had better handle it |
| if (webApp != null) { |
| doCompilation(compiler); |
| return; |
| } |
| |
| // make sure that we've got a srcdir |
| if (src == null) { |
| throw new BuildException("srcdir attribute must be set!", |
| getLocation()); |
| } |
| String [] list = src.list(); |
| if (list.length == 0) { |
| throw new BuildException("srcdir attribute must be set!", |
| getLocation()); |
| } |
| |
| |
| // if the compiler does its own dependency stuff, we just call it right now |
| if (compiler.implementsOwnDependencyChecking()) { |
| doCompilation(compiler); |
| return; |
| } |
| |
| //the remainder of this method is only for compilers that need their dependency work done |
| JspMangler mangler = compiler.createMangler(); |
| |
| // scan source directories and dest directory to build up both copy |
| // lists and compile lists |
| resetFileLists(); |
| int filecount = 0; |
| for (int i = 0; i < list.length; i++) { |
| File srcDir = getProject().resolveFile(list[i]); |
| if (!srcDir.exists()) { |
| throw new BuildException("srcdir \"" + srcDir.getPath() |
| + "\" does not exist!", getLocation()); |
| } |
| DirectoryScanner ds = this.getDirectoryScanner(srcDir); |
| String[] files = ds.getIncludedFiles(); |
| filecount = files.length; |
| scanDir(srcDir, dest, mangler, files); |
| } |
| |
| // compile the source files |
| |
| log("compiling " + compileList.size() + " files", Project.MSG_VERBOSE); |
| |
| if (compileList.size() > 0) { |
| |
| log("Compiling " + compileList.size() + " source file" |
| + (compileList.size() == 1 ? "" : "s") |
| + " to " |
| + dest); |
| doCompilation(compiler); |
| |
| } else { |
| if (filecount == 0) { |
| log("there were no files to compile", Project.MSG_INFO); |
| } else { |
| log("all files are up to date", Project.MSG_VERBOSE); |
| } |
| } |
| } |
| |
| /** |
| * calculate where the files will end up: |
| * this is destDir or it id destDir + the package name |
| */ |
| private File getActualDestDir() { |
| File dest = null; |
| if (packageName == null) { |
| dest = destDir; |
| } else { |
| String path = destDir.getPath() + File.separatorChar |
| + packageName.replace('.', File.separatorChar); |
| dest = new File(path); |
| } |
| return dest; |
| } |
| |
| /** |
| * do the compile |
| */ |
| private void doCompilation(JspCompilerAdapter compiler) |
| throws BuildException { |
| // now we need to populate the compiler adapter |
| compiler.setJspc(this); |
| |
| // finally, lets execute the compiler!! |
| if (!compiler.execute()) { |
| if (failOnError) { |
| throw new BuildException(FAIL_MSG, getLocation()); |
| } else { |
| log(FAIL_MSG, Project.MSG_ERR); |
| } |
| } |
| } |
| |
| /** |
| * Clear the list of files to be compiled and copied.. |
| */ |
| protected void resetFileLists() { |
| compileList.removeAllElements(); |
| } |
| |
| /** |
| * Scans the directory looking for source files to be compiled. |
| * The results are returned in the class variable compileList |
| * @param srcDir the source directory. |
| * @param dest the destination directory. |
| * @param mangler the jsp filename mangler. |
| * @param files the file names to mangle. |
| */ |
| protected void scanDir( |
| File srcDir, File dest, JspMangler mangler, String[] files) { |
| |
| long now = (new Date()).getTime(); |
| |
| for (int i = 0; i < files.length; i++) { |
| String filename = files[i]; |
| File srcFile = new File(srcDir, filename); |
| File javaFile = mapToJavaFile(mangler, srcFile, srcDir, dest); |
| if (javaFile == null) { |
| continue; |
| } |
| |
| if (srcFile.lastModified() > now) { |
| log("Warning: file modified in the future: " + filename, |
| Project.MSG_WARN); |
| } |
| boolean shouldCompile = false; |
| shouldCompile = isCompileNeeded(srcFile, javaFile); |
| if (shouldCompile) { |
| compileList.addElement(srcFile.getAbsolutePath()); |
| javaFiles.addElement(javaFile); |
| } |
| } |
| } |
| |
| /** |
| * Test whether or not compilation is needed. A return value of |
| * <code>true<code> means yes, <code>false</code> means |
| * our tests do not indicate this, but as the TLDs are |
| * not used for dependency checking this is not guaranteed. |
| * The current tests are |
| * <ol> |
| * <li>no dest file |
| * <li>dest file out of date w.r.t source |
| * <li>dest file zero bytes long |
| * </ol> |
| * @param srcFile JSP source file |
| * @param javaFile JSP dest file |
| * @return true if a compile is definately needed. |
| * |
| */ |
| private boolean isCompileNeeded(File srcFile, File javaFile) { |
| boolean shouldCompile = false; |
| if (!javaFile.exists()) { |
| shouldCompile = true; |
| log("Compiling " + srcFile.getPath() |
| + " because java file " + javaFile.getPath() |
| + " does not exist", Project.MSG_VERBOSE); |
| } else { |
| if (srcFile.lastModified() > javaFile.lastModified()) { |
| shouldCompile = true; |
| log("Compiling " + srcFile.getPath() |
| + " because it is out of date with respect to " |
| + javaFile.getPath(), |
| Project.MSG_VERBOSE); |
| } else { |
| if (javaFile.length() == 0) { |
| shouldCompile = true; |
| log("Compiling " + srcFile.getPath() |
| + " because java file " + javaFile.getPath() |
| + " is empty", Project.MSG_VERBOSE); |
| } |
| } |
| } |
| return shouldCompile; |
| } |
| |
| |
| /** |
| * get a filename from our jsp file. |
| * @param mangler the jsp filename managler. |
| * @param srcFile the source file. |
| * @param srcDir the source directory. |
| * @param dest the destination directory. |
| * @return the filename. |
| * @todo support packages and subdirs |
| */ |
| protected File mapToJavaFile(JspMangler mangler, File srcFile, File srcDir, File dest) { |
| if (!srcFile.getName().endsWith(".jsp")) { |
| return null; |
| } |
| String javaFileName = mangler.mapJspToJavaName(srcFile); |
| // String srcFileDir=srcFile.getParent(); |
| return new File(dest, javaFileName); |
| } |
| |
| /** |
| * delete any java output files that are empty |
| * this is to get around a little defect in jasper: when it |
| * fails, it leaves incomplete files around. |
| */ |
| public void deleteEmptyJavaFiles() { |
| if (javaFiles != null) { |
| Enumeration e = javaFiles.elements(); |
| while (e.hasMoreElements()) { |
| File file = (File) e.nextElement(); |
| if (file.exists() && file.length() == 0) { |
| log("deleting empty output file " + file); |
| file.delete(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * static inner class used as a parameter element |
| */ |
| public static class WebAppParameter { |
| |
| /** |
| * the sole option |
| */ |
| private File directory; |
| |
| /** |
| * query current directory |
| * @return the directory. |
| */ |
| public File getDirectory() { |
| return directory; |
| } |
| |
| /** |
| * set directory; alternate syntax |
| * @param directory the base dir. |
| */ |
| public void setBaseDir(File directory) { |
| this.directory = directory; |
| } |
| //end inner class |
| } |
| |
| |
| //end class |
| } |