1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts2.jasper;
19
20 import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
21 import com.opensymphony.xwork2.util.logging.Logger;
22 import com.opensymphony.xwork2.util.logging.LoggerFactory;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.struts2.jasper.compiler.Compiler;
25 import org.apache.struts2.jasper.compiler.*;
26 import org.apache.struts2.jasper.servlet.JspCServletContext;
27
28 import java.io.*;
29 import java.net.URL;
30 import java.net.URLClassLoader;
31 import java.util.*;
32
33 /***
34 * Shell for the jspc compiler. Handles all options associated with the
35 * command line and creates compilation contexts which it then compiles
36 * according to the specified options.
37 * <p/>
38 * This version can process files from a _single_ webapp at once, i.e.
39 * a single docbase can be specified.
40 * <p/>
41 * It can be used as an Ant task using:
42 * <pre>
43 * <taskdef classname="org.apache.struts.jasperJspC" name="jasper2" >
44 * <classpath>
45 * <pathelement location="${java.home}/../lib/tools.jar"/>
46 * <fileset dir="${ENV.CATALINA_HOME}/server/lib">
47 * <include name="*.jar"/>
48 * </fileset>
49 * <fileset dir="${ENV.CATALINA_HOME}/common/lib">
50 * <include name="*.jar"/>
51 * </fileset>
52 * <path refid="myjars"/>
53 * </classpath>
54 * </taskdef>
55 * <p/>
56 * <jasper2 verbose="0"
57 * package="my.package"
58 * uriroot="${webapps.dir}/${webapp.name}"
59 * webXmlFragment="${build.dir}/generated_web.xml"
60 * outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
61 * </pre>
62 *
63 * @author Danno Ferrin
64 * @author Pierre Delisle
65 * @author Costin Manolache
66 * @author Yoav Shapira
67 */
68 public class JspC implements Options {
69 /***
70 * The default Microsoft Internet Explorer class ID.
71 */
72 public static final String DEFAULT_IE_CLASS_ID =
73 "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
74
75 /***
76 * Logger (set by constructor.)
77 */
78 private Logger log;
79
80 private static final String SWITCH_VERBOSE = "-v";
81 private static final String SWITCH_HELP = "-help";
82 private static final String SWITCH_QUIET = "-q";
83 private static final String SWITCH_OUTPUT_DIR = "-d";
84 private static final String SWITCH_IE_CLASS_ID = "-ieplugin";
85 private static final String SWITCH_PACKAGE_NAME = "-p";
86 private static final String SWITCH_CACHE = "-cache";
87 private static final String SWITCH_CLASS_NAME = "-c";
88 private static final String SWITCH_FULL_STOP = "--";
89 private static final String SWITCH_COMPILE = "-compile";
90 private static final String SWITCH_SOURCE = "-source";
91 private static final String SWITCH_TARGET = "-target";
92 private static final String SWITCH_URI_BASE = "-uribase";
93 private static final String SWITCH_URI_ROOT = "-uriroot";
94 private static final String SWITCH_FILE_WEBAPP = "-webapp";
95 private static final String SWITCH_WEBAPP_INC = "-webinc";
96 private static final String SWITCH_WEBAPP_XML = "-webxml";
97 private static final String SWITCH_MAPPED = "-mapped";
98 private static final String SWITCH_XPOWERED_BY = "-xpoweredBy";
99 private static final String SWITCH_TRIM_SPACES = "-trimSpaces";
100 private static final String SWITCH_CLASSPATH = "-classpath";
101 private static final String SWITCH_DIE = "-die";
102 private static final String SWITCH_POOLING = "-poolingEnabled";
103 private static final String SWITCH_ENCODING = "-javaEncoding";
104 private static final String SWITCH_SMAP = "-smap";
105 private static final String SWITCH_DUMP_SMAP = "-dumpsmap";
106
107 private static final String SHOW_SUCCESS = "-s";
108 private static final String LIST_ERRORS = "-l";
109 private static final int NO_WEBXML = 0;
110 private static final int INC_WEBXML = 10;
111 private static final int ALL_WEBXML = 20;
112 private static final int DEFAULT_DIE_LEVEL = 1;
113 private static final int NO_DIE_LEVEL = 0;
114
115 private static final String[] insertBefore =
116 {"</web-app>", "<servlet-mapping>", "<session-config>",
117 "<mime-mapping>", "<welcome-file-list>", "<error-page>", "<taglib>",
118 "<resource-env-ref>", "<resource-ref>", "<security-constraint>",
119 "<login-config>", "<security-role>", "<env-entry>", "<ejb-ref>",
120 "<ejb-local-ref>"};
121
122 private static int die;
123 private String classPath = null;
124 private URLClassLoader loader = null;
125 private boolean trimSpaces = false;
126 private boolean genStringAsCharArray = false;
127 private boolean xpoweredBy;
128 private boolean mappedFile = false;
129 private boolean poolingEnabled = true;
130 private File scratchDir;
131 private String ieClassId = DEFAULT_IE_CLASS_ID;
132 private String targetPackage;
133 private String targetClassName;
134 private String uriBase;
135
136 private int dieLevel;
137 private boolean helpNeeded = false;
138 private boolean compile = false;
139 private boolean smapSuppressed = true;
140 private boolean smapDumped = false;
141 private boolean caching = true;
142 private Map cache = new HashMap();
143
144 private String compiler = null;
145
146 private ClassLoaderInterface classLoaderInterface;
147
148 private String compilerTargetVM = "1.4";
149 private String compilerSourceVM = "1.4";
150
151 private boolean classDebugInfo = true;
152
153 /***
154 * Throw an exception if there's a compilation error, or swallow it.
155 * Default is true to preserve old behavior.
156 */
157 private boolean failOnError = true;
158
159 /***
160 * The file extensions to be handled as JSP files.
161 * Default list is .jsp and .jspx.
162 */
163 private List extensions;
164
165 /***
166 * The pages.
167 */
168 private List pages = new Vector();
169
170 /***
171 * Needs better documentation, this data member does.
172 * True by default.
173 */
174 private boolean errorOnUseBeanInvalidClassAttribute = true;
175
176 /***
177 * The java file encoding. Default
178 * is UTF-8. Added per bugzilla 19622.
179 */
180 private String javaEncoding = "UTF-8";
181
182
183 private String webxmlFile;
184 private int webxmlLevel;
185
186 private Writer mapout;
187 private CharArrayWriter servletout;
188 private CharArrayWriter mappingout;
189
190 /***
191 * The servlet context.
192 */
193 private JspCServletContext context;
194
195 /***
196 * The runtime context.
197 * Maintain a dummy JspRuntimeContext for compiling tag files.
198 */
199 private JspRuntimeContext rctxt;
200
201 /***
202 * Cache for the TLD locations
203 */
204 private TldLocationsCache tldLocationsCache = null;
205
206 private JspConfig jspConfig = null;
207 private TagPluginManager tagPluginManager = null;
208
209 private boolean verbose = false;
210 private boolean listErrors = false;
211 private boolean showSuccess = false;
212 private int argPos;
213 private boolean fullstop = false;
214 private String args[];
215 private String sourceCode;
216
217 public static void main(String arg[]) {
218 if (arg.length == 0) {
219 System.out.println(Localizer.getMessage("jspc.usage"));
220 } else {
221 try {
222 JspC jspc = new JspC();
223 jspc.setArgs(arg);
224 if (jspc.helpNeeded) {
225 System.out.println(Localizer.getMessage("jspc.usage"));
226 } else {
227 jspc.execute();
228 }
229 } catch (JasperException je) {
230 System.err.println(je);
231
232 if (die != NO_DIE_LEVEL) {
233 System.exit(die);
234 }
235 }
236 }
237 }
238
239 /***
240 * Constructor.
241 */
242 public JspC() {
243 log = LoggerFactory.getLogger(getClass());
244 }
245
246 public String getSourceCode() {
247 return sourceCode;
248 }
249
250 public void setClassLoaderInterface(ClassLoaderInterface classLoaderInterface) {
251 this.classLoaderInterface = classLoaderInterface;
252 }
253
254 public void setArgs(String[] arg) throws JasperException {
255 args = arg;
256 String tok;
257
258 dieLevel = NO_DIE_LEVEL;
259 die = dieLevel;
260
261 while ((tok = nextArg()) != null) {
262 if (tok.equals(SWITCH_VERBOSE)) {
263 verbose = true;
264 showSuccess = true;
265 listErrors = true;
266 } else if (tok.equals(SWITCH_OUTPUT_DIR)) {
267 tok = nextArg();
268 setOutputDir(tok);
269 } else if (tok.equals(SWITCH_PACKAGE_NAME)) {
270 targetPackage = nextArg();
271 } else if (tok.equals(SWITCH_COMPILE)) {
272 compile = true;
273 } else if (tok.equals(SWITCH_CLASS_NAME)) {
274 targetClassName = nextArg();
275 } else if (tok.equals(SWITCH_URI_BASE)) {
276 uriBase = nextArg();
277 } else if (tok.equals(SHOW_SUCCESS)) {
278 showSuccess = true;
279 } else if (tok.equals(LIST_ERRORS)) {
280 listErrors = true;
281 } else if (tok.equals(SWITCH_WEBAPP_INC)) {
282 webxmlFile = nextArg();
283 if (webxmlFile != null) {
284 webxmlLevel = INC_WEBXML;
285 }
286 } else if (tok.equals(SWITCH_WEBAPP_XML)) {
287 webxmlFile = nextArg();
288 if (webxmlFile != null) {
289 webxmlLevel = ALL_WEBXML;
290 }
291 } else if (tok.equals(SWITCH_MAPPED)) {
292 mappedFile = true;
293 } else if (tok.equals(SWITCH_XPOWERED_BY)) {
294 xpoweredBy = true;
295 } else if (tok.equals(SWITCH_TRIM_SPACES)) {
296 setTrimSpaces(true);
297 } else if (tok.equals(SWITCH_CACHE)) {
298 tok = nextArg();
299 if ("false".equals(tok)) {
300 caching = false;
301 } else {
302 caching = true;
303 }
304 } else if (tok.equals(SWITCH_CLASSPATH)) {
305 setClassPath(nextArg());
306 } else if (tok.startsWith(SWITCH_DIE)) {
307 try {
308 dieLevel = Integer.parseInt(
309 tok.substring(SWITCH_DIE.length()));
310 } catch (NumberFormatException nfe) {
311 dieLevel = DEFAULT_DIE_LEVEL;
312 }
313 die = dieLevel;
314 } else if (tok.equals(SWITCH_HELP)) {
315 helpNeeded = true;
316 } else if (tok.equals(SWITCH_POOLING)) {
317 tok = nextArg();
318 if ("false".equals(tok)) {
319 poolingEnabled = false;
320 } else {
321 poolingEnabled = true;
322 }
323 } else if (tok.equals(SWITCH_ENCODING)) {
324 setJavaEncoding(nextArg());
325 } else if (tok.equals(SWITCH_SOURCE)) {
326 setCompilerSourceVM(nextArg());
327 } else if (tok.equals(SWITCH_TARGET)) {
328 setCompilerTargetVM(nextArg());
329 } else if (tok.equals(SWITCH_SMAP)) {
330 smapSuppressed = false;
331 } else if (tok.equals(SWITCH_DUMP_SMAP)) {
332 smapDumped = true;
333 } else {
334 if (tok.startsWith("-")) {
335 throw new JasperException("Unrecognized option: " + tok +
336 ". Use -help for help.");
337 }
338 if (!fullstop) {
339 argPos--;
340 }
341
342 break;
343 }
344 }
345
346
347 while (true) {
348 String file = nextFile();
349 if (file == null) {
350 break;
351 }
352 pages.add(file);
353 }
354 }
355
356 public boolean getKeepGenerated() {
357
358 return true;
359 }
360
361 public boolean getTrimSpaces() {
362 return trimSpaces;
363 }
364
365 public void setTrimSpaces(boolean ts) {
366 this.trimSpaces = ts;
367 }
368
369 public boolean isPoolingEnabled() {
370 return poolingEnabled;
371 }
372
373 public void setPoolingEnabled(boolean poolingEnabled) {
374 this.poolingEnabled = poolingEnabled;
375 }
376
377 public boolean isXpoweredBy() {
378 return xpoweredBy;
379 }
380
381 public void setXpoweredBy(boolean xpoweredBy) {
382 this.xpoweredBy = xpoweredBy;
383 }
384
385 public boolean getErrorOnUseBeanInvalidClassAttribute() {
386 return errorOnUseBeanInvalidClassAttribute;
387 }
388
389 public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
390 errorOnUseBeanInvalidClassAttribute = b;
391 }
392
393 public int getTagPoolSize() {
394 return Constants.MAX_POOL_SIZE;
395 }
396
397 /***
398 * Are we supporting HTML mapped servlets?
399 */
400 public boolean getMappedFile() {
401 return mappedFile;
402 }
403
404
405 public Object getProtectionDomain() {
406 return null;
407 }
408
409 public boolean getSendErrorToClient() {
410
411 return true;
412 }
413
414 public void setClassDebugInfo(boolean b) {
415 classDebugInfo = b;
416 }
417
418 public boolean getClassDebugInfo() {
419
420 return classDebugInfo;
421 }
422
423 /***
424 * @see Options#isCaching()
425 */
426 public boolean isCaching() {
427 return caching;
428 }
429
430 /***
431 * @see Options#isCaching()
432 */
433 public void setCaching(boolean caching) {
434 this.caching = caching;
435 }
436
437 /***
438 * @see Options#getCache()
439 */
440 public Map getCache() {
441 return cache;
442 }
443
444 /***
445 * Background compilation check intervals in seconds
446 */
447 public int getCheckInterval() {
448 return 0;
449 }
450
451 /***
452 * Modification test interval.
453 */
454 public int getModificationTestInterval() {
455 return 0;
456 }
457
458 /***
459 * Is Jasper being used in development mode?
460 */
461 public boolean getDevelopment() {
462 return false;
463 }
464
465 /***
466 * Is the generation of SMAP info for JSR45 debuggin suppressed?
467 */
468 public boolean isSmapSuppressed() {
469 return smapSuppressed;
470 }
471
472 /***
473 * Set smapSuppressed flag.
474 */
475 public void setSmapSuppressed(boolean smapSuppressed) {
476 this.smapSuppressed = smapSuppressed;
477 }
478
479
480 /***
481 * Should SMAP info for JSR45 debugging be dumped to a file?
482 */
483 public boolean isSmapDumped() {
484 return smapDumped;
485 }
486
487 /***
488 * Set smapSuppressed flag.
489 */
490 public void setSmapDumped(boolean smapDumped) {
491 this.smapDumped = smapDumped;
492 }
493
494
495 /***
496 * Determines whether text strings are to be generated as char arrays,
497 * which improves performance in some cases.
498 *
499 * @param genStringAsCharArray true if text strings are to be generated as
500 * char arrays, false otherwise
501 */
502 public void setGenStringAsCharArray(boolean genStringAsCharArray) {
503 this.genStringAsCharArray = genStringAsCharArray;
504 }
505
506 /***
507 * Indicates whether text strings are to be generated as char arrays.
508 *
509 * @return true if text strings are to be generated as char arrays, false
510 * otherwise
511 */
512 public boolean genStringAsCharArray() {
513 return genStringAsCharArray;
514 }
515
516 /***
517 * Sets the class-id value to be sent to Internet Explorer when using
518 * <jsp:plugin> tags.
519 *
520 * @param ieClassId Class-id value
521 */
522 public void setIeClassId(String ieClassId) {
523 this.ieClassId = ieClassId;
524 }
525
526 /***
527 * Gets the class-id value that is sent to Internet Explorer when using
528 * <jsp:plugin> tags.
529 *
530 * @return Class-id value
531 */
532 public String getIeClassId() {
533 return ieClassId;
534 }
535
536 public File getScratchDir() {
537 return scratchDir;
538 }
539
540 public Class getJspCompilerPlugin() {
541
542 return null;
543 }
544
545 public String getJspCompilerPath() {
546
547 return null;
548 }
549
550 /***
551 * Compiler to use.
552 */
553 public String getCompiler() {
554 return compiler;
555 }
556
557 public void setCompiler(String c) {
558 compiler = c;
559 }
560
561 /***
562 * @see Options#getCompilerTargetVM
563 */
564 public String getCompilerTargetVM() {
565 return compilerTargetVM;
566 }
567
568 public void setCompilerTargetVM(String vm) {
569 compilerTargetVM = vm;
570 }
571
572 /***
573 * @see Options#getCompilerSourceVM()
574 */
575 public String getCompilerSourceVM() {
576 return compilerSourceVM;
577 }
578
579 /***
580 * @see Options#getCompilerSourceVM()
581 */
582 public void setCompilerSourceVM(String vm) {
583 compilerSourceVM = vm;
584 }
585
586 public TldLocationsCache getTldLocationsCache() {
587 return tldLocationsCache;
588 }
589
590 /***
591 * Returns the encoding to use for
592 * java files. The default is UTF-8.
593 *
594 * @return String The encoding
595 */
596 public String getJavaEncoding() {
597 return javaEncoding;
598 }
599
600 /***
601 * Sets the encoding to use for
602 * java files.
603 *
604 * @param encodingName The name, e.g. "UTF-8"
605 */
606 public void setJavaEncoding(String encodingName) {
607 javaEncoding = encodingName;
608 }
609
610 public boolean getFork() {
611 return false;
612 }
613
614 public String getClassPath() {
615 if (classPath != null)
616 return classPath;
617 return System.getProperty("java.class.path");
618 }
619
620 public void setClassPath(String s) {
621 classPath = s;
622 }
623
624 /***
625 * Returns the list of file extensions
626 * that are treated as JSP files.
627 *
628 * @return The list of extensions
629 */
630 public List getExtensions() {
631 return extensions;
632 }
633
634 /***
635 * Adds the given file extension to the
636 * list of extensions handled as JSP files.
637 *
638 * @param extension The extension to add, e.g. "myjsp"
639 */
640 protected void addExtension(final String extension) {
641 if (extension != null) {
642 if (extensions == null) {
643 extensions = new Vector();
644 }
645
646 extensions.add(extension);
647 }
648 }
649
650 /***
651 * Parses comma-separated list of JSP files to be processed. If the argument
652 * is null, nothing is done.
653 * <p/>
654 * <p>Each file is interpreted relative to uriroot, unless it is absolute,
655 * in which case it must start with uriroot.</p>
656 *
657 * @param jspFiles Comma-separated list of JSP files to be processed
658 */
659 public void setJspFiles(final String jspFiles) {
660 if (jspFiles == null) {
661 return;
662 }
663
664 StringTokenizer tok = new StringTokenizer(jspFiles, ",");
665 while (tok.hasMoreTokens()) {
666 pages.add(tok.nextToken());
667 }
668 }
669
670 /***
671 * Sets the compile flag.
672 *
673 * @param b Flag value
674 */
675 public void setCompile(final boolean b) {
676 compile = b;
677 }
678
679 /***
680 * Sets the verbosity level. The actual number doesn't
681 * matter: if it's greater than zero, the verbose flag will
682 * be true.
683 *
684 * @param level Positive means verbose
685 */
686 public void setVerbose(final int level) {
687 if (level > 0) {
688 verbose = true;
689 showSuccess = true;
690 listErrors = true;
691 }
692 }
693
694 public void setValidateXml(boolean b) {
695 org.apache.struts2.jasper.xmlparser.ParserUtils.validating = b;
696 }
697
698 public void setListErrors(boolean b) {
699 listErrors = b;
700 }
701
702 public void setOutputDir(String s) {
703 if (s != null) {
704 scratchDir = resolveFile(s).getAbsoluteFile();
705 } else {
706 scratchDir = null;
707 }
708 }
709
710 public void setPackage(String p) {
711 targetPackage = p;
712 }
713
714 /***
715 * Class name of the generated file ( without package ).
716 * Can only be used if a single file is converted.
717 * XXX Do we need this feature ?
718 */
719 public void setClassName(String p) {
720 targetClassName = p;
721 }
722
723 /***
724 * File where we generate a web.xml fragment with the class definitions.
725 */
726 public void setWebXmlFragment(String s) {
727 webxmlFile = resolveFile(s).getAbsolutePath();
728 webxmlLevel = INC_WEBXML;
729 }
730
731 /***
732 * File where we generate a complete web.xml with the class definitions.
733 */
734 public void setWebXml(String s) {
735 webxmlFile = resolveFile(s).getAbsolutePath();
736 webxmlLevel = ALL_WEBXML;
737 }
738
739 /***
740 * Set the option that throws an exception in case of a compilation error.
741 */
742 public void setFailOnError(final boolean b) {
743 failOnError = b;
744 }
745
746 public boolean getFailOnError() {
747 return failOnError;
748 }
749
750 /***
751 * Obtain JSP configuration informantion specified in web.xml.
752 */
753 public JspConfig getJspConfig() {
754 return jspConfig;
755 }
756
757 public TagPluginManager getTagPluginManager() {
758 return tagPluginManager;
759 }
760
761 public void generateWebMapping(String file, JspCompilationContext clctxt)
762 throws IOException {
763 if (log.isDebugEnabled()) {
764 log.debug("Generating web mapping for file " + file
765 + " using compilation context " + clctxt);
766 }
767
768 String className = clctxt.getServletClassName();
769 String packageName = clctxt.getServletPackageName();
770
771 String thisServletName;
772 if ("".equals(packageName)) {
773 thisServletName = className;
774 } else {
775 thisServletName = packageName + '.' + className;
776 }
777
778 if (servletout != null) {
779 servletout.write("\n <servlet>\n <servlet-name>");
780 servletout.write(thisServletName);
781 servletout.write("</servlet-name>\n <servlet-class>");
782 servletout.write(thisServletName);
783 servletout.write("</servlet-class>\n </servlet>\n");
784 }
785 if (mappingout != null) {
786 mappingout.write("\n <servlet-mapping>\n <servlet-name>");
787 mappingout.write(thisServletName);
788 mappingout.write("</servlet-name>\n <url-pattern>");
789 mappingout.write(file.replace('//', '/'));
790 mappingout.write("</url-pattern>\n </servlet-mapping>\n");
791
792 }
793 }
794
795 private void processFile(String file)
796 throws JasperException {
797 if (log.isDebugEnabled()) {
798 log.debug("Processing file: " + file);
799 }
800
801 ClassLoader originalClassLoader = null;
802
803 try {
804
805 if (scratchDir == null) {
806 String temp = System.getProperty("java.io.tmpdir");
807 if (temp == null) {
808 temp = "";
809 }
810 scratchDir = new File(new File(temp).getAbsolutePath());
811 }
812
813 String jspUri = file.replace('//', '/');
814 JspCompilationContext clctxt = new JspCompilationContext
815 (jspUri, false, this, context, null, rctxt, classLoaderInterface);
816
817
818 if ((targetClassName != null) && (targetClassName.length() > 0)) {
819 clctxt.setServletClassName(targetClassName);
820 targetClassName = null;
821 }
822 if (targetPackage != null) {
823 clctxt.setServletPackageName(targetPackage);
824 }
825
826 originalClassLoader = Thread.currentThread().getContextClassLoader();
827 if (loader == null) {
828 initClassLoader(clctxt);
829 }
830 Thread.currentThread().setContextClassLoader(loader);
831
832 clctxt.setClassLoader(loader);
833 clctxt.setClassPath(classPath);
834
835 Compiler clc = clctxt.createCompiler();
836
837
838
839
840
841 if (clc.isOutDated(compile)) {
842 if (log.isDebugEnabled()) {
843 log.debug(jspUri + " is out dated, compiling...");
844 }
845
846 clc.compile(compile, true);
847 }
848
849
850 generateWebMapping(file, clctxt);
851 if (showSuccess) {
852 log.info("Built File: " + file);
853 }
854
855 this.sourceCode = clctxt.getSourceCode();
856
857 } catch (JasperException je) {
858 Throwable rootCause = je;
859 while (rootCause instanceof JasperException
860 && ((JasperException) rootCause).getRootCause() != null) {
861 rootCause = ((JasperException) rootCause).getRootCause();
862 }
863 if (rootCause != je) {
864 log.error(Localizer.getMessage("jspc.error.generalException",
865 file),
866 rootCause);
867 }
868
869
870 if (getFailOnError()) {
871 throw je;
872 } else {
873 log.error(je.getMessage(), je);
874 ;
875 }
876
877 } catch (Exception e) {
878 if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) {
879 log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist",
880 e.getMessage()));
881 }
882 throw new JasperException(e);
883 } finally {
884 if (originalClassLoader != null) {
885 Thread.currentThread().setContextClassLoader(originalClassLoader);
886 }
887 }
888 }
889
890 public Set<String> getTldAbsolutePaths() {
891 return tldLocationsCache.getAbsolutePathsOfLocations();
892 }
893
894
895 /***
896 * Executes the compilation.
897 *
898 * @throws JasperException If an error occurs
899 */
900 public void execute() throws JasperException {
901 if (log.isDebugEnabled()) {
902 log.debug("execute() starting for " + pages.size() + " pages.");
903 }
904
905 try {
906 if (context == null) {
907 initServletContext();
908 }
909
910 initWebXml();
911
912 Iterator iter = pages.iterator();
913 while (iter.hasNext()) {
914 String nextjsp = iter.next().toString();
915
916 processFile(nextjsp);
917 }
918
919 completeWebXml();
920 } catch (JasperException je) {
921 Throwable rootCause = je;
922 while (rootCause instanceof JasperException
923 && ((JasperException) rootCause).getRootCause() != null) {
924 rootCause = ((JasperException) rootCause).getRootCause();
925 }
926 if (rootCause != je) {
927 rootCause.printStackTrace();
928 }
929 throw je;
930 } finally {
931 if (loader != null) {
932 LogFactory.release(loader);
933 }
934 }
935 }
936
937
938
939 private String nextArg() {
940 if ((argPos >= args.length)
941 || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) {
942 return null;
943 } else {
944 return args[argPos++];
945 }
946 }
947
948 private String nextFile() {
949 if (fullstop) argPos++;
950 if (argPos >= args.length) {
951 return null;
952 } else {
953 return args[argPos++];
954 }
955 }
956
957 private void initWebXml() {
958 try {
959 if (webxmlLevel >= INC_WEBXML) {
960 File fmapings = new File(webxmlFile);
961 mapout = new FileWriter(fmapings);
962 servletout = new CharArrayWriter();
963 mappingout = new CharArrayWriter();
964 } else {
965 mapout = null;
966 servletout = null;
967 mappingout = null;
968 }
969 if (webxmlLevel >= ALL_WEBXML) {
970 mapout.write(Localizer.getMessage("jspc.webxml.header"));
971 mapout.flush();
972 } else if ((webxmlLevel >= INC_WEBXML)) {
973 mapout.write(Localizer.getMessage("jspc.webinc.header"));
974 mapout.flush();
975 }
976 } catch (IOException ioe) {
977 mapout = null;
978 servletout = null;
979 mappingout = null;
980 }
981 }
982
983 private void completeWebXml() {
984 if (mapout != null) {
985 try {
986 servletout.writeTo(mapout);
987 mappingout.writeTo(mapout);
988 if (webxmlLevel >= ALL_WEBXML) {
989 mapout.write(Localizer.getMessage("jspc.webxml.footer"));
990 } else if ((webxmlLevel >= INC_WEBXML)) {
991 mapout.write(Localizer.getMessage("jspc.webinc.footer"));
992 }
993 mapout.close();
994 } catch (IOException ioe) {
995
996 }
997 }
998 }
999
1000 private void initServletContext() {
1001
1002 context = new JspCServletContext
1003 (new PrintWriter(System.out),
1004 classLoaderInterface);
1005 tldLocationsCache = new TldLocationsCache(context, true);
1006
1007 rctxt = new JspRuntimeContext(context, this);
1008 jspConfig = new JspConfig(context);
1009 tagPluginManager = new TagPluginManager(context);
1010 }
1011
1012 /***
1013 * Initializes the classloader as/if needed for the given
1014 * compilation context.
1015 *
1016 * @param clctxt The compilation context
1017 * @throws IOException If an error occurs
1018 */
1019 private void initClassLoader(JspCompilationContext clctxt)
1020 throws IOException {
1021
1022 classPath = getClassPath();
1023
1024 ClassLoader jspcLoader = getClass().getClassLoader();
1025
1026 ArrayList urls = new ArrayList();
1027 StringTokenizer tokenizer = new StringTokenizer(classPath,
1028 File.pathSeparator);
1029 while (tokenizer.hasMoreTokens()) {
1030 String path = tokenizer.nextToken();
1031 try {
1032 File libFile = new File(path);
1033 urls.add(libFile.toURL());
1034 } catch (IOException ioe) {
1035
1036
1037
1038 throw new RuntimeException(ioe.toString());
1039 }
1040 }
1041
1042
1043
1044 URL urlsA[] = new URL[urls.size()];
1045 urls.toArray(urlsA);
1046 loader = new URLClassLoader(urlsA, this.getClass().getClassLoader());
1047
1048 }
1049
1050 /***
1051 * Resolves the relative or absolute pathname correctly
1052 * in both Ant and command-line situations. If Ant launched
1053 * us, we should use the basedir of the current project
1054 * to resolve relative paths.
1055 * <p/>
1056 * See Bugzilla 35571.
1057 *
1058 * @param s The file
1059 * @return The file resolved
1060 */
1061 protected File resolveFile(final String s) {
1062
1063 return new File(s);
1064 }
1065 }