1
17 package org.apache.jasper;
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.net.JarURLConnection;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.net.URLClassLoader;
26 import java.net.URLConnection;
27 import java.util.Set;
28 import java.util.jar.JarEntry;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.jsp.tagext.TagInfo;
32
33 import org.apache.jasper.compiler.Compiler;
34 import org.apache.jasper.compiler.JspRuntimeContext;
35 import org.apache.jasper.compiler.JspUtil;
36 import org.apache.jasper.compiler.Localizer;
37 import org.apache.jasper.compiler.ServletWriter;
38 import org.apache.jasper.servlet.JasperLoader;
39 import org.apache.jasper.servlet.JspServletWrapper;
40 import org.apache.juli.logging.Log;
41 import org.apache.juli.logging.LogFactory;
42 import org.apache.tomcat.Jar;
43 import org.apache.tomcat.util.descriptor.tld.TldResourcePath;
44
45
59 public class JspCompilationContext {
60
61 private final Log log = LogFactory.getLog(JspCompilationContext.class);
62
63 private String className;
64 private final String jspUri;
65 private String basePackageName;
66 private String derivedPackageName;
67 private String servletJavaFileName;
68 private String javaPath;
69 private String classFileName;
70 private ServletWriter writer;
71 private final Options options;
72 private final JspServletWrapper jsw;
73 private Compiler jspCompiler;
74 private String classPath;
75
76 private final String baseURI;
77 private String outputDir;
78 private final ServletContext context;
79 private ClassLoader loader;
80
81 private final JspRuntimeContext rctxt;
82
83 private volatile boolean removed = false;
84
85
86
87 private volatile URLClassLoader jspLoader;
88 private URL baseUrl;
89 private Class<?> servletClass;
90
91 private final boolean isTagFile;
92 private boolean protoTypeMode;
93 private TagInfo tagInfo;
94 private Jar tagJar;
95
96
97 public JspCompilationContext(String jspUri, Options options,
98 ServletContext context, JspServletWrapper jsw,
99 JspRuntimeContext rctxt) {
100 this(jspUri, null, options, context, jsw, rctxt, null, false);
101 }
102
103 public JspCompilationContext(String tagfile, TagInfo tagInfo,
104 Options options, ServletContext context, JspServletWrapper jsw,
105 JspRuntimeContext rctxt, Jar tagJar) {
106 this(tagfile, tagInfo, options, context, jsw, rctxt, tagJar, true);
107 }
108
109 private JspCompilationContext(String jspUri, TagInfo tagInfo,
110 Options options, ServletContext context, JspServletWrapper jsw,
111 JspRuntimeContext rctxt, Jar tagJar, boolean isTagFile) {
112
113 this.jspUri = canonicalURI(jspUri);
114 this.options = options;
115 this.jsw = jsw;
116 this.context = context;
117
118 String baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1);
119
120 if (baseURI.isEmpty()) {
121 baseURI = "/";
122 } else if (baseURI.charAt(0) != '/') {
123
124
125 baseURI = "/" + baseURI;
126 }
127 if (baseURI.charAt(baseURI.length() - 1) != '/') {
128 baseURI += '/';
129 }
130 this.baseURI = baseURI;
131
132 this.rctxt = rctxt;
133 this.basePackageName = Constants.JSP_PACKAGE_NAME;
134
135 this.tagInfo = tagInfo;
136 this.tagJar = tagJar;
137 this.isTagFile = isTagFile;
138 }
139
140
141
142
143
144
145
148 public String getClassPath() {
149 if( classPath != null ) {
150 return classPath;
151 }
152 return rctxt.getClassPath();
153 }
154
155
159 public void setClassPath(String classPath) {
160 this.classPath = classPath;
161 }
162
163
168 public ClassLoader getClassLoader() {
169 if( loader != null ) {
170 return loader;
171 }
172 return rctxt.getParentClassLoader();
173 }
174
175 public void setClassLoader(ClassLoader loader) {
176 this.loader = loader;
177 }
178
179 public ClassLoader getJspLoader() {
180 if( jspLoader == null ) {
181 jspLoader = new JasperLoader
182 (new URL[] {baseUrl},
183 getClassLoader(),
184 rctxt.getPermissionCollection());
185 }
186 return jspLoader;
187 }
188
189 public void clearJspLoader() {
190 jspLoader = null;
191 }
192
193
194
195
196
202 public String getOutputDir() {
203 if (outputDir == null) {
204 createOutputDir();
205 }
206
207 return outputDir;
208 }
209
210
216 public Compiler createCompiler() {
217 if (jspCompiler != null ) {
218 return jspCompiler;
219 }
220 jspCompiler = null;
221 if (options.getCompilerClassName() != null) {
222 jspCompiler = createCompiler(options.getCompilerClassName());
223 } else {
224 if (options.getCompiler() == null) {
225 jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
226 if (jspCompiler == null) {
227 jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
228 }
229 } else {
230 jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
231 if (jspCompiler == null) {
232 jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
233 }
234 }
235 }
236 if (jspCompiler == null) {
237 throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler.config",
238 options.getCompilerClassName(), options.getCompiler()));
239 }
240 jspCompiler.init(this, jsw);
241 return jspCompiler;
242 }
243
244 protected Compiler createCompiler(String className) {
245 Compiler compiler = null;
246 try {
247 compiler = (Compiler) Class.forName(className).getConstructor().newInstance();
248 } catch (NoClassDefFoundError | ClassNotFoundException e) {
249 if (log.isDebugEnabled()) {
250 log.debug(Localizer.getMessage("jsp.error.compiler"), e);
251 }
252 } catch (ReflectiveOperationException e) {
253 log.warn(Localizer.getMessage("jsp.error.compiler"), e);
254 }
255 return compiler;
256 }
257
258 public Compiler getCompiler() {
259 return jspCompiler;
260 }
261
262
263
264
270 public String resolveRelativeUri(String uri) {
271
272
273 if (uri.startsWith("/") || uri.startsWith(File.separator)) {
274 return uri;
275 } else {
276 return baseURI + uri;
277 }
278 }
279
280
287 public java.io.InputStream getResourceAsStream(String res) {
288 return context.getResourceAsStream(canonicalURI(res));
289 }
290
291
292 public URL getResource(String res) throws MalformedURLException {
293 return context.getResource(canonicalURI(res));
294 }
295
296
297 public Set<String> getResourcePaths(String path) {
298 return context.getResourcePaths(canonicalURI(path));
299 }
300
301
307 public String getRealPath(String path) {
308 if (context != null) {
309 return context.getRealPath(path);
310 }
311 return path;
312 }
313
314
321 public Jar getTagFileJar() {
322 return this.tagJar;
323 }
324
325 public void setTagFileJar(Jar tagJar) {
326 this.tagJar = tagJar;
327 }
328
329
330
331
336 public String getServletClassName() {
337
338 if (className != null) {
339 return className;
340 }
341
342 if (isTagFile) {
343 className = tagInfo.getTagClassName();
344 int lastIndex = className.lastIndexOf('.');
345 if (lastIndex != -1) {
346 className = className.substring(lastIndex + 1);
347 }
348 } else {
349 int iSep = jspUri.lastIndexOf('/') + 1;
350 className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep));
351 }
352 return className;
353 }
354
355 public void setServletClassName(String className) {
356 this.className = className;
357 }
358
359
364 public String getJspFile() {
365 return jspUri;
366 }
367
368
369 public Long getLastModified(String resource) {
370 return getLastModified(resource, tagJar);
371 }
372
373
374 public Long getLastModified(String resource, Jar tagJar) {
375 long result = -1;
376 URLConnection uc = null;
377 try {
378 if (tagJar != null) {
379 if (resource.startsWith("/")) {
380 resource = resource.substring(1);
381 }
382 result = tagJar.getLastModified(resource);
383 } else {
384 URL jspUrl = getResource(resource);
385 if (jspUrl == null) {
386 incrementRemoved();
387 return Long.valueOf(result);
388 }
389 uc = jspUrl.openConnection();
390 if (uc instanceof JarURLConnection) {
391 JarEntry jarEntry = ((JarURLConnection) uc).getJarEntry();
392 if (jarEntry != null) {
393 result = jarEntry.getTime();
394 } else {
395 result = uc.getLastModified();
396 }
397 } else {
398 result = uc.getLastModified();
399 }
400 }
401 } catch (IOException e) {
402 if (log.isDebugEnabled()) {
403 log.debug(Localizer.getMessage(
404 "jsp.error.lastModified", getJspFile()), e);
405 }
406 result = -1;
407 } finally {
408 if (uc != null) {
409 try {
410 uc.getInputStream().close();
411 } catch (IOException e) {
412 if (log.isDebugEnabled()) {
413 log.debug(Localizer.getMessage(
414 "jsp.error.lastModified", getJspFile()), e);
415 }
416 result = -1;
417 }
418 }
419 }
420 return Long.valueOf(result);
421 }
422
423 public boolean isTagFile() {
424 return isTagFile;
425 }
426
427 public TagInfo getTagInfo() {
428 return tagInfo;
429 }
430
431 public void setTagInfo(TagInfo tagi) {
432 tagInfo = tagi;
433 }
434
435
441 public boolean isPrototypeMode() {
442 return protoTypeMode;
443 }
444
445 public void setPrototypeMode(boolean pm) {
446 protoTypeMode = pm;
447 }
448
449
455 public String getServletPackageName() {
456 if (isTagFile()) {
457 String className = tagInfo.getTagClassName();
458 int lastIndex = className.lastIndexOf('.');
459 String packageName = "";
460 if (lastIndex != -1) {
461 packageName = className.substring(0, lastIndex);
462 }
463 return packageName;
464 } else {
465 String dPackageName = getDerivedPackageName();
466 if (dPackageName.length() == 0) {
467 return basePackageName;
468 }
469 return basePackageName + '.' + getDerivedPackageName();
470 }
471 }
472
473 protected String getDerivedPackageName() {
474 if (derivedPackageName == null) {
475 int iSep = jspUri.lastIndexOf('/');
476 derivedPackageName = (iSep > 0) ?
477 JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : "";
478 }
479 return derivedPackageName;
480 }
481
482
486 public String getBasePackageName() {
487 return basePackageName;
488 }
489
490
494 public void setBasePackageName(String basePackageName) {
495 this.basePackageName = basePackageName;
496 }
497
498
502 public String getServletJavaFileName() {
503 if (servletJavaFileName == null) {
504 servletJavaFileName = getOutputDir() + getServletClassName() + ".java";
505 }
506 return servletJavaFileName;
507 }
508
509
512 public Options getOptions() {
513 return options;
514 }
515
516 public ServletContext getServletContext() {
517 return context;
518 }
519
520 public JspRuntimeContext getRuntimeContext() {
521 return rctxt;
522 }
523
524
527 public String getJavaPath() {
528
529 if (javaPath != null) {
530 return javaPath;
531 }
532
533 if (isTagFile()) {
534 String tagName = tagInfo.getTagClassName();
535 javaPath = tagName.replace('.', '/') + ".java";
536 } else {
537 javaPath = getServletPackageName().replace('.', '/') + '/' +
538 getServletClassName() + ".java";
539 }
540 return javaPath;
541 }
542
543 public String getClassFileName() {
544 if (classFileName == null) {
545 classFileName = getOutputDir() + getServletClassName() + ".class";
546 }
547 return classFileName;
548 }
549
550
553 public ServletWriter getWriter() {
554 return writer;
555 }
556
557 public void setWriter(ServletWriter writer) {
558 this.writer = writer;
559 }
560
561
570 public TldResourcePath getTldResourcePath(String uri) {
571 return getOptions().getTldCache().getTldResourcePath(uri);
572 }
573
574
577 public boolean keepGenerated() {
578 return getOptions().getKeepGenerated();
579 }
580
581
582
583 public void incrementRemoved() {
584 if (removed == false && rctxt != null) {
585 rctxt.removeWrapper(jspUri);
586 }
587 removed = true;
588 }
589
590 public boolean isRemoved() {
591 return removed;
592 }
593
594
595
596 public void compile() throws JasperException, FileNotFoundException {
597 createCompiler();
598 if (jspCompiler.isOutDated()) {
599 if (isRemoved()) {
600 throw new FileNotFoundException(jspUri);
601 }
602 try {
603 jspCompiler.removeGeneratedFiles();
604 jspLoader = null;
605 jspCompiler.compile();
606 jsw.setReload(true);
607 jsw.setCompilationException(null);
608 } catch (JasperException ex) {
609
610 jsw.setCompilationException(ex);
611 if (options.getDevelopment() && options.getRecompileOnFail()) {
612
613 jsw.setLastModificationTest(-1);
614 }
615 throw ex;
616 } catch (FileNotFoundException fnfe) {
617
618 throw fnfe;
619 } catch (Exception ex) {
620 JasperException je = new JasperException(
621 Localizer.getMessage("jsp.error.unable.compile"),
622 ex);
623
624 jsw.setCompilationException(je);
625 throw je;
626 }
627 }
628 }
629
630
631
632 public Class<?> load() throws JasperException {
633 try {
634 getJspLoader();
635
636 String name = getFQCN();
637 servletClass = jspLoader.loadClass(name);
638 } catch (ClassNotFoundException cex) {
639 throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
640 cex);
641 } catch (Exception ex) {
642 throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"),
643 ex);
644 }
645 removed = false;
646 return servletClass;
647 }
648
649 public String getFQCN() {
650 String name;
651 if (isTagFile()) {
652 name = tagInfo.getTagClassName();
653 } else {
654 name = getServletPackageName() + "." + getServletClassName();
655 }
656 return name;
657 }
658
659
660
661 private static final Object outputDirLock = new Object();
662
663 public void checkOutputDir() {
664 if (outputDir != null) {
665 if (!(new File(outputDir)).exists()) {
666 makeOutputDir();
667 }
668 } else {
669 createOutputDir();
670 }
671 }
672
673 protected boolean makeOutputDir() {
674 synchronized(outputDirLock) {
675 File outDirFile = new File(outputDir);
676 return (outDirFile.mkdirs() || outDirFile.isDirectory());
677 }
678 }
679
680 protected void createOutputDir() {
681 String path = null;
682 if (isTagFile()) {
683 String tagName = tagInfo.getTagClassName();
684 path = tagName.replace('.', File.separatorChar);
685 path = path.substring(0, path.lastIndexOf(File.separatorChar));
686 } else {
687 path = getServletPackageName().replace('.',File.separatorChar);
688 }
689
690
691 try {
692 File base = options.getScratchDir();
693 baseUrl = base.toURI().toURL();
694 outputDir = base.getAbsolutePath() + File.separator + path +
695 File.separator;
696 if (!makeOutputDir()) {
697 throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"));
698 }
699 } catch (MalformedURLException e) {
700 throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e);
701 }
702 }
703
704 protected static final boolean isPathSeparator(char c) {
705 return (c == '/' || c == '\\');
706 }
707
708 protected static final String canonicalURI(String s) {
709 if (s == null) {
710 return null;
711 }
712 StringBuilder result = new StringBuilder();
713 final int len = s.length();
714 int pos = 0;
715 while (pos < len) {
716 char c = s.charAt(pos);
717 if ( isPathSeparator(c) ) {
718
722 while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) {
723 ++pos;
724 }
725
726 if (pos+1 < len && s.charAt(pos+1) == '.') {
727
730 if (pos+2 >= len) {
731 break;
732 }
733
734 switch (s.charAt(pos+2)) {
735
739 case '/':
740 case '\\':
741 pos += 2;
742 continue;
743
744
748 case '.':
749
750 if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) {
751 pos += 3;
752 int separatorPos = result.length()-1;
753 while (separatorPos >= 0 &&
754 ! isPathSeparator(result
755 .charAt(separatorPos))) {
756 --separatorPos;
757 }
758 if (separatorPos >= 0) {
759 result.setLength(separatorPos);
760 }
761 continue;
762 }
763 }
764 }
765 }
766 result.append(c);
767 ++pos;
768 }
769 return result.toString();
770 }
771 }
772