1. /*
  2. * Copyright 2000,2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.jsp;
  18. //apache/ant imports
  19. import java.io.File;
  20. import java.util.Date;
  21. import java.util.StringTokenizer;
  22. import java.util.Vector;
  23. import org.apache.tools.ant.BuildException;
  24. import org.apache.tools.ant.DirectoryScanner;
  25. import org.apache.tools.ant.Project;
  26. import org.apache.tools.ant.taskdefs.Java;
  27. import org.apache.tools.ant.taskdefs.MatchingTask;
  28. import org.apache.tools.ant.types.Path;
  29. /**
  30. * Precompiles JSP's using WebLogic's JSP compiler (weblogic.jspc).
  31. *
  32. *
  33. * Tested only on Weblogic 4.5.1 - NT4.0 and Solaris 5.7
  34. *
  35. * required attributes
  36. * src : root of source tree for JSP, ie, the document root for your weblogic server
  37. * dest : root of destination directory, what you have set as
  38. * WorkingDir in the weblogic properties
  39. * package : start package name under which your JSP's would be compiled
  40. *
  41. * other attributes
  42. * classpath
  43. *
  44. * A classpath should be set which contains the weblogic classes as well as all
  45. * application classes referenced by the JSP. The system classpath is also
  46. * appended when the jspc is called, so you may choose to put everything in
  47. * the classpath while calling Ant. However, since presumably the JSP's will
  48. * reference classes being build by Ant, it would be better to explicitly add
  49. * the classpath in the task
  50. *
  51. * The task checks timestamps on the JSP's and the generated classes, and compiles
  52. * only those files that have changed.
  53. *
  54. * It follows the weblogic naming convention of putting classes in
  55. * <b> _dirName/_fileName.class for dirname/fileName.jsp </b>
  56. *
  57. * Limitation: It compiles the files thru the Classic compiler only.
  58. * Limitation: Since it is my experience that weblogic jspc throws out of
  59. * memory error on being given too many files at one go, it is
  60. * called multiple times with one jsp file each.
  61. *
  62. * <pre>
  63. * example
  64. * <target name="jspcompile" depends="compile">
  65. * <wljspc src="c:\\weblogic\\myserver\\public_html"
  66. * dest="c:\\weblogic\\myserver\\serverclasses" package="myapp.jsp">
  67. * <classpath>
  68. * <pathelement location="${weblogic.classpath}" />
  69. * <pathelement path="${compile.dest}" />
  70. * </classpath>
  71. *
  72. * </wljspc>
  73. * </target>
  74. * </pre>
  75. *
  76. */
  77. public class WLJspc extends MatchingTask {
  78. //TODO Test on other versions of weblogic
  79. //TODO add more attributes to the task, to take care of all jspc options
  80. //TODO Test on Unix
  81. /** root of compiled files tree */
  82. private File destinationDirectory;
  83. /** root of source files tree */
  84. private File sourceDirectory;
  85. /** package under which resultant classes will reside */
  86. private String destinationPackage;
  87. /** classpath used to compile the jsp files. */
  88. private Path compileClasspath;
  89. //private String compilerPath; //fully qualified name for the compiler executable
  90. private String pathToPackage = "";
  91. private Vector filesToDo = new Vector();
  92. public void execute() throws BuildException {
  93. if (!destinationDirectory.isDirectory()) {
  94. throw new BuildException("destination directory "
  95. + destinationDirectory.getPath() + " is not valid");
  96. }
  97. if (!sourceDirectory.isDirectory()) {
  98. throw new BuildException("src directory "
  99. + sourceDirectory.getPath() + " is not valid");
  100. }
  101. if (destinationPackage == null) {
  102. throw new BuildException("package attribute must be present.",
  103. getLocation());
  104. }
  105. pathToPackage
  106. = this.destinationPackage.replace('.', File.separatorChar);
  107. // get all the files in the sourceDirectory
  108. DirectoryScanner ds = super.getDirectoryScanner(sourceDirectory);
  109. //use the systemclasspath as well, to include the ant jar
  110. if (compileClasspath == null) {
  111. compileClasspath = new Path(getProject());
  112. }
  113. compileClasspath = compileClasspath.concatSystemClasspath();
  114. String[] files = ds.getIncludedFiles();
  115. //Weblogic.jspc calls System.exit() ... have to fork
  116. // Therefore, takes loads of time
  117. // Can pass directories at a time (*.jsp) but easily runs out of
  118. // memory on hefty dirs (even on a Sun)
  119. Java helperTask = (Java) getProject().createTask("java");
  120. helperTask.setFork(true);
  121. helperTask.setClassname("weblogic.jspc");
  122. helperTask.setTaskName(getTaskName());
  123. String[] args = new String[12];
  124. File jspFile = null;
  125. String parents = "";
  126. int j = 0;
  127. //XXX this array stuff is a remnant of prev trials.. gotta remove.
  128. args[j++] = "-d";
  129. args[j++] = destinationDirectory.getAbsolutePath().trim();
  130. args[j++] = "-docroot";
  131. args[j++] = sourceDirectory.getAbsolutePath().trim();
  132. args[j++] = "-keepgenerated"; //TODO: Parameterise ??
  133. //Call compiler as class... dont want to fork again
  134. //Use classic compiler -- can be parameterised?
  135. args[j++] = "-compilerclass";
  136. args[j++] = "sun.tools.javac.Main";
  137. //Weblogic jspc does not seem to work unless u explicitly set this...
  138. // Does not take the classpath from the env....
  139. // Am i missing something about the Java task??
  140. args[j++] = "-classpath";
  141. args[j++] = compileClasspath.toString();
  142. this.scanDir(files);
  143. log("Compiling " + filesToDo.size() + " JSP files");
  144. for (int i = 0; i < filesToDo.size(); i++) {
  145. //XXX
  146. // All this to get package according to weblogic standards
  147. // Can be written better... this is too hacky!
  148. // Careful.. similar code in scanDir , but slightly different!!
  149. String filename = (String) filesToDo.elementAt(i);
  150. jspFile = new File(filename);
  151. args[j] = "-package";
  152. parents = jspFile.getParent();
  153. if ((parents != null) && (!("").equals(parents))) {
  154. parents = this.replaceString(parents, File.separator, "_.");
  155. args[j + 1] = destinationPackage + "." + "_" + parents;
  156. } else {
  157. args[j + 1] = destinationPackage;
  158. }
  159. args[j + 2] = sourceDirectory + File.separator + filename;
  160. helperTask.clearArgs();
  161. for (int x = 0; x < j + 3; x++) {
  162. helperTask.createArg().setValue(args[x]);
  163. }
  164. helperTask.setClasspath(compileClasspath);
  165. if (helperTask.executeJava() != 0) {
  166. log(filename + " failed to compile", Project.MSG_WARN);
  167. }
  168. }
  169. }
  170. /**
  171. * Set the classpath to be used for this compilation.
  172. *
  173. */
  174. public void setClasspath(Path classpath) {
  175. if (compileClasspath == null) {
  176. compileClasspath = classpath;
  177. } else {
  178. compileClasspath.append(classpath);
  179. }
  180. }
  181. /**
  182. * Maybe creates a nested classpath element.
  183. */
  184. public Path createClasspath() {
  185. if (compileClasspath == null) {
  186. compileClasspath = new Path(getProject());
  187. }
  188. return compileClasspath;
  189. }
  190. /**
  191. * Set the directory containing the source jsp's
  192. *
  193. *
  194. * @param dirName the directory containg the source jsp's
  195. */
  196. public void setSrc(File dirName) {
  197. sourceDirectory = dirName;
  198. }
  199. /**
  200. * Set the directory containing the source jsp's
  201. *
  202. *
  203. * @param dirName the directory containg the source jsp's
  204. */
  205. public void setDest(File dirName) {
  206. destinationDirectory = dirName;
  207. }
  208. /**
  209. * Set the package under which the compiled classes go
  210. *
  211. * @param packageName the package name for the clases
  212. */
  213. public void setPackage(String packageName) {
  214. destinationPackage = packageName;
  215. }
  216. protected void scanDir(String files[]) {
  217. long now = (new Date()).getTime();
  218. File jspFile = null;
  219. String parents = null;
  220. String pack = "";
  221. for (int i = 0; i < files.length; i++) {
  222. File srcFile = new File(this.sourceDirectory, files[i]);
  223. //XXX
  224. // All this to convert source to destination directory according
  225. // to weblogic standards Can be written better... this is too hacky!
  226. jspFile = new File(files[i]);
  227. parents = jspFile.getParent();
  228. if ((parents != null) && (!("").equals(parents))) {
  229. parents = this.replaceString(parents, File.separator, "_/");
  230. pack = pathToPackage + File.separator + "_" + parents;
  231. } else {
  232. pack = pathToPackage;
  233. }
  234. String filePath = pack + File.separator + "_";
  235. int startingIndex = files[i].lastIndexOf(File.separator) != -1
  236. ? files[i].lastIndexOf(File.separator) + 1 : 0;
  237. int endingIndex = files[i].indexOf(".jsp");
  238. if (endingIndex == -1) {
  239. log("Skipping " + files[i] + ". Not a JSP",
  240. Project.MSG_VERBOSE);
  241. continue;
  242. }
  243. filePath += files[i].substring(startingIndex, endingIndex);
  244. filePath += ".class";
  245. File classFile = new File(this.destinationDirectory, filePath);
  246. if (srcFile.lastModified() > now) {
  247. log("Warning: file modified in the future: "
  248. + files[i], Project.MSG_WARN);
  249. }
  250. if (srcFile.lastModified() > classFile.lastModified()) {
  251. filesToDo.addElement(files[i]);
  252. log("Recompiling File " + files[i], Project.MSG_VERBOSE);
  253. }
  254. }
  255. }
  256. protected String replaceString(String inpString, String escapeChars,
  257. String replaceChars) {
  258. String localString = "";
  259. int numTokens = 0;
  260. StringTokenizer st = new StringTokenizer(inpString, escapeChars, true);
  261. numTokens = st.countTokens();
  262. for (int i = 0; i < numTokens; i++) {
  263. String test = st.nextToken();
  264. test = (test.equals(escapeChars) ? replaceChars : test);
  265. localString += test;
  266. }
  267. return localString;
  268. }
  269. }