| /* |
| * 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 |
| * |
| * https://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; |
| |
| //apache/ant imports |
| import java.io.File; |
| import java.time.Instant; |
| import java.util.List; |
| import java.util.StringTokenizer; |
| 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.Java; |
| import org.apache.tools.ant.taskdefs.MatchingTask; |
| import org.apache.tools.ant.types.Path; |
| |
| /** |
| * Precompiles JSP's using WebLogic's JSP compiler (weblogic.jspc). |
| * |
| * Tested only on WebLogic 4.5.1 - NT4.0 and Solaris 5.7 |
| * |
| * required attributes |
| * src : root of source tree for JSP, ie, the document root for your WebLogic server |
| * dest : root of destination directory, what you have set as |
| * WorkingDir in the WebLogic properties |
| * package : start package name under which your JSP's would be compiled |
| * |
| * other attributes |
| * classpath |
| * |
| * A classpath should be set which contains the WebLogic classes as well as all |
| * application classes referenced by the JSP. The system classpath is also |
| * appended when the jspc is called, so you may choose to put everything in |
| * the classpath while calling Ant. However, since presumably the JSP's will |
| * reference classes being build by Ant, it would be better to explicitly add |
| * the classpath in the task |
| * |
| * The task checks timestamps on the JSP's and the generated classes, and compiles |
| * only those files that have changed. |
| * |
| * It follows the WebLogic naming convention of putting classes in |
| * <b> _dirName/_fileName.class for dirname/fileName.jsp </b> |
| * |
| * Limitation: It compiles the files through the Classic compiler only. |
| * Limitation: Since it is my experience that WebLogic jspc throws out of |
| * memory error on being given too many files at one go, it is |
| * called multiple times with one jsp file each. |
| * |
| * <pre> |
| * example |
| * <target name="jspcompile" depends="compile"> |
| * <wljspc src="c:\\weblogic\\myserver\\public_html" |
| * dest="c:\\weblogic\\myserver\\serverclasses" package="myapp.jsp"> |
| * <classpath> |
| * <pathelement location="${weblogic.classpath}" /> |
| * <pathelement path="${compile.dest}" /> |
| * </classpath> |
| * |
| * </wljspc> |
| * </target> |
| * </pre> |
| * |
| */ |
| |
| public class WLJspc extends MatchingTask { |
| //TODO Test on other versions of WebLogic |
| //TODO add more attributes to the task, to take care of all jspc options |
| //TODO Test on Unix |
| |
| /** root of compiled files tree */ |
| private File destinationDirectory; |
| |
| /** root of source files tree */ |
| private File sourceDirectory; |
| |
| /** package under which resultant classes will reside */ |
| private String destinationPackage; |
| |
| /** classpath used to compile the jsp files. */ |
| private Path compileClasspath; |
| |
| //private String compilerPath; //fully qualified name for the compiler executable |
| |
| private String pathToPackage = ""; |
| private List<String> filesToDo = new Vector<>(); |
| |
| /** |
| * Run the task. |
| * @throws BuildException if there is an error. |
| */ |
| @Override |
| public void execute() throws BuildException { |
| if (!destinationDirectory.isDirectory()) { |
| throw new BuildException("destination directory %s is not valid", |
| destinationDirectory.getPath()); |
| } |
| |
| if (!sourceDirectory.isDirectory()) { |
| throw new BuildException("src directory %s is not valid", |
| sourceDirectory.getPath()); |
| } |
| |
| if (destinationPackage == null) { |
| throw new BuildException("package attribute must be present.", |
| getLocation()); |
| } |
| |
| pathToPackage |
| = this.destinationPackage.replace('.', File.separatorChar); |
| // get all the files in the sourceDirectory |
| DirectoryScanner ds = super.getDirectoryScanner(sourceDirectory); |
| |
| //use the systemclasspath as well, to include the ant jar |
| if (compileClasspath == null) { |
| compileClasspath = new Path(getProject()); |
| } |
| |
| compileClasspath = compileClasspath.concatSystemClasspath(); |
| |
| // WebLogic jspc calls System.exit() ... have to fork |
| // Therefore, takes loads of time |
| // Can pass directories at a time (*.jsp) but easily runs out of |
| // memory on hefty dirs (even on a Sun) |
| Java helperTask = new Java(this); |
| helperTask.setFork(true); |
| helperTask.setClassname("weblogic.jspc"); |
| helperTask.setTaskName(getTaskName()); |
| // CheckStyle:MagicNumber OFF |
| String[] args = new String[12]; |
| // CheckStyle:MagicNumber ON |
| |
| int j = 0; |
| //TODO this array stuff is a remnant of prev trials.. gotta remove. |
| args[j++] = "-d"; |
| args[j++] = destinationDirectory.getAbsolutePath().trim(); |
| args[j++] = "-docroot"; |
| args[j++] = sourceDirectory.getAbsolutePath().trim(); |
| args[j++] = "-keepgenerated"; |
| //Call compiler as class... dont want to fork again |
| //Use classic compiler -- can be parameterised? |
| args[j++] = "-compilerclass"; |
| args[j++] = "sun.tools.javac.Main"; |
| // WebLogic jspc does not seem to work unless u explicitly set this... |
| // Does not take the classpath from the env.... |
| // Am i missing something about the Java task?? |
| args[j++] = "-classpath"; |
| args[j++] = compileClasspath.toString(); |
| |
| this.scanDir(ds.getIncludedFiles()); |
| log("Compiling " + filesToDo.size() + " JSP files"); |
| |
| for (String filename : filesToDo) { |
| //TODO |
| // All this to get package according to WebLogic standards |
| // Can be written better... this is too hacky! |
| // Careful.. similar code in scanDir, but slightly different!! |
| File jspFile = new File(filename); |
| args[j] = "-package"; |
| String parents = jspFile.getParent(); |
| if (parents == null || parents.isEmpty()) { |
| args[j + 1] = destinationPackage; |
| } else { |
| parents = this.replaceString(parents, File.separator, "_."); |
| args[j + 1] = destinationPackage + "." + "_" + parents; |
| } |
| |
| args[j + 2] = sourceDirectory + File.separator + filename; |
| helperTask.clearArgs(); |
| |
| // CheckStyle:MagicNumber OFF |
| for (int x = 0; x < j + 3; x++) { |
| helperTask.createArg().setValue(args[x]); |
| } |
| // CheckStyle:MagicNumber ON |
| |
| helperTask.setClasspath(compileClasspath); |
| if (helperTask.executeJava() != 0) { |
| log(filename + " failed to compile", Project.MSG_WARN); |
| } |
| } |
| } |
| |
| /** |
| * Set the classpath to be used for this compilation. |
| * @param classpath the classpath to use. |
| */ |
| public void setClasspath(Path classpath) { |
| if (compileClasspath == null) { |
| compileClasspath = classpath; |
| } else { |
| compileClasspath.append(classpath); |
| } |
| } |
| |
| /** |
| * Maybe creates a nested classpath element. |
| * @return a path to be configured. |
| */ |
| public Path createClasspath() { |
| if (compileClasspath == null) { |
| compileClasspath = new Path(getProject()); |
| } |
| return compileClasspath; |
| } |
| |
| /** |
| * Set the directory containing the source jsp's |
| * |
| * |
| * @param dirName the directory containing the source jsp's |
| */ |
| public void setSrc(File dirName) { |
| sourceDirectory = dirName; |
| } |
| |
| /** |
| * Set the directory containing the source jsp's |
| * |
| * |
| * @param dirName the directory containing the source jsp's |
| */ |
| public void setDest(File dirName) { |
| destinationDirectory = dirName; |
| } |
| |
| /** |
| * Set the package under which the compiled classes go |
| * |
| * @param packageName the package name for the classes |
| */ |
| public void setPackage(String packageName) { |
| destinationPackage = packageName; |
| } |
| |
| /** |
| * Scan the array of files and add the jsp |
| * files that need to be compiled to the filesToDo field. |
| * @param files the files to scan. |
| */ |
| protected void scanDir(String[] files) { |
| long now = Instant.now().toEpochMilli(); |
| for (String file : files) { |
| File srcFile = new File(this.sourceDirectory, file); |
| //TODO |
| // All this to convert source to destination directory according |
| // to WebLogic standards - can be written better... this is too hacky! |
| File jspFile = new File(file); |
| String parents = jspFile.getParent(); |
| |
| String pack; |
| if (parents == null || parents.isEmpty()) { |
| pack = pathToPackage; |
| } else { |
| parents = this.replaceString(parents, File.separator, "_/"); |
| pack = pathToPackage + File.separator + "_" + parents; |
| } |
| |
| String filePath = pack + File.separator + "_"; |
| int startingIndex = file.lastIndexOf(File.separator) != -1 |
| ? file.lastIndexOf(File.separator) + 1 : 0; |
| int endingIndex = file.indexOf(".jsp"); |
| if (endingIndex == -1) { |
| log("Skipping " + file + ". Not a JSP", |
| Project.MSG_VERBOSE); |
| continue; |
| } |
| |
| filePath += file.substring(startingIndex, endingIndex); |
| filePath += ".class"; |
| File classFile = new File(this.destinationDirectory, filePath); |
| |
| if (srcFile.lastModified() > now) { |
| log("Warning: file modified in the future: " |
| + file, Project.MSG_WARN); |
| } |
| if (srcFile.lastModified() > classFile.lastModified()) { |
| filesToDo.add(file); |
| log("Recompiling File " + file, Project.MSG_VERBOSE); |
| } |
| } |
| } |
| |
| /** |
| * Replace occurrences of a string with a replacement string. |
| * @param inpString the string to convert. |
| * @param escapeChars the string to replace. |
| * @param replaceChars the string to place. |
| * @return the converted string. |
| */ |
| protected String replaceString(String inpString, String escapeChars, |
| String replaceChars) { |
| StringBuilder localString = new StringBuilder(); |
| StringTokenizer st = new StringTokenizer(inpString, escapeChars, true); |
| int numTokens = st.countTokens(); |
| for (int i = 0; i < numTokens; i++) { |
| String test = st.nextToken(); |
| test = test.equals(escapeChars) ? replaceChars : test; |
| localString.append(test); |
| } |
| return localString.toString(); |
| } |
| } |