Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/jasper/JspCompilationContext.java


1   /*
2    * Copyright 1999,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.jasper;
18  
19  import java.io.File;
20  import java.io.FileNotFoundException;
21  import java.net.MalformedURLException;
22  import java.net.URL;
23  import java.net.URLClassLoader;
24  import java.util.Hashtable;
25  import java.util.Set;
26  
27  import javax.servlet.ServletContext;
28  import javax.servlet.jsp.tagext.TagInfo;
29  
30  import org.apache.jasper.compiler.Compiler;
31  import org.apache.jasper.compiler.JspRuntimeContext;
32  import org.apache.jasper.compiler.JspUtil;
33  import org.apache.jasper.compiler.Localizer;
34  import org.apache.jasper.compiler.ServletWriter;
35  import org.apache.jasper.servlet.JasperLoader;
36  import org.apache.jasper.servlet.JspServletWrapper;
37  
38  /**
39   * A place holder for various things that are used through out the JSP
40   * engine. This is a per-request/per-context data structure. Some of
41   * the instance variables are set at different points.
42   *
43   * Most of the path-related stuff is here - mangling names, versions, dirs,
44   * loading resources and dealing with uris. 
45   *
46   * @author Anil K. Vijendran
47   * @author Harish Prabandham
48   * @author Pierre Delisle
49   * @author Costin Manolache
50   * @author Kin-man Chung
51   */
52  public class JspCompilationContext {
53  
54      protected org.apache.commons.logging.Log log =
55          org.apache.commons.logging.LogFactory.getLog(JspCompilationContext.class);
56  
57      private Hashtable tagFileJarUrls;
58      private boolean isPackagedTagFile;
59  
60      private String className;
61      private String jspUri;
62      private boolean isErrPage;
63      private String basePackageName;
64      private String derivedPackageName;
65      private String servletJavaFileName;
66      private String javaPath;
67      private String classFileName;
68      private String contentType;
69      private ServletWriter writer;
70      private Options options;
71      private JspServletWrapper jsw;
72      private Compiler jspCompiler;
73      private String classPath;
74  
75      private String baseURI;
76      private String baseOutputDir;
77      private String outputDir;
78      private ServletContext context;
79      private URLClassLoader loader;
80  
81      private JspRuntimeContext rctxt;
82  
83      private int removed = 0;
84  
85      private URLClassLoader jspLoader;
86      private URL baseUrl;
87      private Class servletClass;
88  
89      private boolean isTagFile;
90      private boolean protoTypeMode;
91      private TagInfo tagInfo;
92      private URL tagFileJarUrl;
93  
94      // jspURI _must_ be relative to the context
95      public JspCompilationContext(String jspUri,
96                                   boolean isErrPage,
97                                   Options options,
98                                   ServletContext context,
99                                   JspServletWrapper jsw,
100                                  JspRuntimeContext rctxt) {
101 
102         this.jspUri = canonicalURI(jspUri);
103         this.isErrPage = isErrPage;
104         this.options = options;
105         this.jsw = jsw;
106         this.context = context;
107 
108         this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1);
109         // hack fix for resolveRelativeURI
110         if (baseURI == null) {
111             baseURI = "/";
112         } else if (baseURI.charAt(0) != '/') {
113             // strip the basde slash since it will be combined with the
114             // uriBase to generate a file
115             baseURI = "/" + baseURI;
116         }
117         if (baseURI.charAt(baseURI.length() - 1) != '/') {
118             baseURI += '/';
119         }
120 
121         this.rctxt = rctxt;
122         this.tagFileJarUrls = new Hashtable();
123         this.basePackageName = Constants.JSP_PACKAGE_NAME;
124     }
125 
126     public JspCompilationContext(String tagfile,
127                                  TagInfo tagInfo, 
128                                  Options options,
129                                  ServletContext context,
130                                  JspServletWrapper jsw,
131                                  JspRuntimeContext rctxt,
132                                  URL tagFileJarUrl) {
133         this(tagfile, false, options, context, jsw, rctxt);
134         this.isTagFile = true;
135         this.tagInfo = tagInfo;
136         this.tagFileJarUrl = tagFileJarUrl;
137         if (tagFileJarUrl != null) {
138             isPackagedTagFile = true;
139         }
140     }
141 
142     /* ==================== Methods to override ==================== */
143     
144     /** ---------- Class path and loader ---------- */
145 
146     /**
147      * The classpath that is passed off to the Java compiler. 
148      */
149     public String getClassPath() {
150         if( classPath != null )
151             return classPath;
152         return rctxt.getClassPath();
153     }
154 
155     /**
156      * The classpath that is passed off to the Java compiler. 
157      */
158     public void setClassPath(String classPath) {
159         this.classPath = classPath;
160     }
161 
162     /**
163      * What class loader to use for loading classes while compiling
164      * this JSP?
165      */
166     public ClassLoader getClassLoader() {
167         if( loader != null )
168             return loader;
169         return rctxt.getParentClassLoader();
170     }
171 
172     public void setClassLoader(URLClassLoader loader) {
173         this.loader = loader;
174     }
175 
176     public ClassLoader getJspLoader() {
177         if( jspLoader == null ) {
178             jspLoader = new JasperLoader
179             (new URL[] {baseUrl},
180                     getClassLoader(),
181                     rctxt.getPermissionCollection(),
182                     rctxt.getCodeSource());
183         }
184         return jspLoader;
185     }
186 
187     /** ---------- Input/Output  ---------- */
188     
189     /**
190      * The output directory to generate code into.  The output directory
191      * is make up of the scratch directory, which is provide in Options,
192      * plus the directory derived from the package name.
193      */
194     public String getOutputDir() {
195   if (outputDir == null) {
196       createOutputDir();
197   }
198 
199         return outputDir;
200     }
201 
202     /**
203      * Create a "Compiler" object based on some init param data. This
204      * is not done yet. Right now we're just hardcoding the actual
205      * compilers that are created. 
206      */
207     public Compiler createCompiler() throws JasperException {
208         if (jspCompiler != null ) {
209             return jspCompiler;
210         }
211         jspCompiler = null;
212         if (options.getCompiler() == null) {
213             jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
214             if (jspCompiler == null) {
215                 jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
216             }
217         } else {
218             jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
219             if (jspCompiler == null) {
220                 jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
221             }
222         }
223         if (jspCompiler == null) {
224             throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler"));
225         }
226         jspCompiler.init(this, jsw);
227         return jspCompiler;
228     }
229 
230     private Compiler createCompiler(String className) {
231         Compiler compiler = null; 
232         try {
233             compiler = (Compiler) Class.forName(className).newInstance();
234         } catch (Throwable t) {
235             if (log.isDebugEnabled()) {
236                 log.debug(Localizer.getMessage("jsp.error.compiler"), t);
237             }
238         }
239         return compiler;
240     }
241     
242     public Compiler getCompiler() {
243         return jspCompiler;
244     }
245 
246     /** ---------- Access resources in the webapp ---------- */
247 
248     /** 
249      * Get the full value of a URI relative to this compilations context
250      * uses current file as the base.
251      */
252     public String resolveRelativeUri(String uri) {
253         // sometimes we get uri's massaged from File(String), so check for
254         // a root directory deperator char
255         if (uri.startsWith("/") || uri.startsWith(File.separator)) {
256             return uri;
257         } else {
258             return baseURI + uri;
259         }
260     }
261 
262     /**
263      * Gets a resource as a stream, relative to the meanings of this
264      * context's implementation.
265      * @return a null if the resource cannot be found or represented 
266      *         as an InputStream.
267      */
268     public java.io.InputStream getResourceAsStream(String res) {
269         return context.getResourceAsStream(canonicalURI(res));
270     }
271 
272 
273     public URL getResource(String res) throws MalformedURLException {
274         return context.getResource(canonicalURI(res));
275     }
276 
277     public Set getResourcePaths(String path) {
278         return context.getResourcePaths(canonicalURI(path));
279     }
280 
281     /** 
282      * Gets the actual path of a URI relative to the context of
283      * the compilation.
284      */
285     public String getRealPath(String path) {
286         if (context != null) {
287             return context.getRealPath(path);
288         }
289         return path;
290     }
291 
292     /**
293      * Returns the tag-file-name-to-JAR-file map of this compilation unit,
294      * which maps tag file names to the JAR files in which the tag files are
295      * packaged.
296      *
297      * The map is populated when parsing the tag-file elements of the TLDs
298      * of any imported taglibs. 
299      */
300     public Hashtable getTagFileJarUrls() {
301         return this.tagFileJarUrls;
302     }
303 
304     /**
305      * Returns the JAR file in which the tag file for which this
306      * JspCompilationContext was created is packaged, or null if this
307      * JspCompilationContext does not correspond to a tag file, or if the
308      * corresponding tag file is not packaged in a JAR.
309      */
310     public URL getTagFileJarUrl() {
311         return this.tagFileJarUrl;
312     }
313 
314     /* ==================== Common implementation ==================== */
315 
316     /**
317      * Just the class name (does not include package name) of the
318      * generated class. 
319      */
320     public String getServletClassName() {
321 
322         if (className != null) {
323             return className;
324         }
325 
326         if (isTagFile) {
327             className = tagInfo.getTagClassName();
328             int lastIndex = className.lastIndexOf('.');
329             if (lastIndex != -1) {
330                 className = className.substring(lastIndex + 1);
331             }
332         } else {
333             int iSep = jspUri.lastIndexOf('/') + 1;
334             className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep));
335         }
336         return className;
337     }
338 
339     public void setServletClassName(String className) {
340         this.className = className;
341     }
342     
343     /**
344      * Path of the JSP URI. Note that this is not a file name. This is
345      * the context rooted URI of the JSP file. 
346      */
347     public String getJspFile() {
348         return jspUri;
349     }
350 
351     /**
352      * Are we processing something that has been declared as an
353      * errorpage? 
354      */
355     public boolean isErrorPage() {
356         return isErrPage;
357     }
358 
359     public void setErrorPage(boolean isErrPage) {
360         this.isErrPage = isErrPage;
361     }
362 
363     public boolean isTagFile() {
364         return isTagFile;
365     }
366 
367     public TagInfo getTagInfo() {
368         return tagInfo;
369     }
370 
371     public void setTagInfo(TagInfo tagi) {
372         tagInfo = tagi;
373     }
374 
375     /**
376      * True if we are compiling a tag file in prototype mode.
377      * ie we only generate codes with class for the tag handler with empty
378      * method bodies.
379      */
380     public boolean isPrototypeMode() {
381         return protoTypeMode;
382     }
383 
384     public void setPrototypeMode(boolean pm) {
385         protoTypeMode = pm;
386     }
387 
388     /**
389      * Package name for the generated class is make up of the base package
390      * name, which is user settable, and the derived package name.  The
391      * derived package name directly mirrors the file heirachy of the JSP page.
392      */
393     public String getServletPackageName() {
394         if (isTagFile()) {
395             String className = tagInfo.getTagClassName();
396             int lastIndex = className.lastIndexOf('.');
397             String pkgName = "";
398             if (lastIndex != -1) {
399                 pkgName = className.substring(0, lastIndex);
400             }
401             return pkgName;
402         } else {
403             String dPackageName = getDerivedPackageName();
404             if (dPackageName.length() == 0) {
405                 return basePackageName;
406             }
407             return basePackageName + '.' + getDerivedPackageName();
408         }
409     }
410 
411     private String getDerivedPackageName() {
412         if (derivedPackageName == null) {
413             int iSep = jspUri.lastIndexOf('/');
414             derivedPackageName = (iSep > 0) ?
415                     JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : "";
416         }
417         return derivedPackageName;
418     }
419       
420     /**
421      * The package name into which the servlet class is generated.
422      */
423     public void setServletPackageName(String servletPackageName) {
424         this.basePackageName = servletPackageName;
425     }
426 
427     /**
428      * Full path name of the Java file into which the servlet is being
429      * generated. 
430      */
431     public String getServletJavaFileName() {
432 
433         if (servletJavaFileName == null) {
434             servletJavaFileName =
435     getOutputDir() + getServletClassName() + ".java";
436         } else {
437             // Make sure output dir exists
438             makeOutputDir();
439         }
440         return servletJavaFileName;
441     }
442 
443     public void setServletJavaFileName(String servletJavaFileName) {
444         this.servletJavaFileName = servletJavaFileName;
445     }
446 
447     /**
448      * Get hold of the Options object for this context. 
449      */
450     public Options getOptions() {
451         return options;
452     }
453 
454     public ServletContext getServletContext() {
455         return context;
456     }
457 
458     public JspRuntimeContext getRuntimeContext() {
459         return rctxt;
460     }
461 
462     /**
463      * Path of the Java file relative to the work directory.
464      */
465     public String getJavaPath() {
466 
467         if (javaPath != null) {
468             return javaPath;
469         }
470 
471         if (isTagFile()) {
472       String tagName = tagInfo.getTagClassName();
473             javaPath = tagName.replace('.', '/') + ".java";
474         } else {
475             javaPath = getServletPackageName().replace('.', '/') + '/' +
476                        getServletClassName() + ".java";
477   }
478         return javaPath;
479     }
480 
481     public String getClassFileName() {
482 
483         if (classFileName == null) {
484             classFileName = getOutputDir() + getServletClassName() + ".class";
485         } else {
486             // Make sure output dir exists
487             makeOutputDir();
488         }
489         return classFileName;
490     }
491 
492     /**
493      * Get the content type of this JSP.
494      *
495      * Content type includes content type and encoding.
496      */
497     public String getContentType() {
498         return contentType;
499     }
500 
501     public void setContentType(String contentType) {
502         this.contentType = contentType;
503     }
504 
505     /**
506      * Where is the servlet being generated?
507      */
508     public ServletWriter getWriter() {
509         return writer;
510     }
511 
512     public void setWriter(ServletWriter writer) {
513         this.writer = writer;
514     }
515 
516     /**
517      * Gets the 'location' of the TLD associated with the given taglib 'uri'.
518      * 
519      * @return An array of two Strings: The first element denotes the real
520      * path to the TLD. If the path to the TLD points to a jar file, then the
521      * second element denotes the name of the TLD entry in the jar file.
522      * Returns null if the given uri is not associated with any tag library
523      * 'exposed' in the web application.
524      */
525     public String[] getTldLocation(String uri) throws JasperException {
526         String[] location = 
527             getOptions().getTldLocationsCache().getLocation(uri);
528         return location;
529     }
530 
531     /**
532      * Are we keeping generated code around?
533      */
534     public boolean keepGenerated() {
535         return getOptions().getKeepGenerated();
536     }
537 
538     // ==================== Removal ==================== 
539 
540     public void incrementRemoved() {
541         if (removed > 1) {
542             jspCompiler.removeGeneratedFiles();
543             if( rctxt != null )
544                 rctxt.removeWrapper(jspUri);
545         }
546         removed++;
547     }
548 
549     public boolean isRemoved() {
550         if (removed > 1 ) {
551             return true;
552         }
553         return false;
554     }
555 
556     // ==================== Compile and reload ====================
557     
558     public void compile() throws JasperException, FileNotFoundException {
559         createCompiler();
560         if (isPackagedTagFile || jspCompiler.isOutDated()) {
561             try {
562                 jspLoader = null;
563                 jspCompiler.compile();
564                 jsw.setReload(true);
565                 jsw.setCompilationException(null);
566             } catch (JasperException ex) {
567                 // Cache compilation exception
568                 jsw.setCompilationException(ex);
569                 throw ex;
570             } catch (Exception ex) {
571                 ex.printStackTrace();
572                 JasperException je = new JasperException(
573                             Localizer.getMessage("jsp.error.unable.compile"),
574                             ex);
575                 // Cache compilation exception
576                 jsw.setCompilationException(je);
577                 throw je;
578             }
579         }
580     }
581 
582     // ==================== Manipulating the class ====================
583 
584     public Class load() 
585         throws JasperException, FileNotFoundException
586     {
587         try {
588             getJspLoader();
589             
590             String name;
591             if (isTagFile()) {
592                 name = tagInfo.getTagClassName();
593             } else {
594                 name = getServletPackageName() + "." + getServletClassName();
595             }
596             servletClass = jspLoader.loadClass(name);
597         } catch (ClassNotFoundException cex) {
598             throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
599                                       cex);
600         } catch (Exception ex) {
601             throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"),
602                                       ex);
603         }
604         removed = 0;
605         return servletClass;
606     }
607 
608     // ==================== Private methods ==================== 
609 
610     static Object outputDirLock = new Object();
611 
612     private void makeOutputDir() {
613         synchronized(outputDirLock) {
614             File outDirFile = new File(outputDir);
615             outDirFile.mkdirs();
616         }
617     }
618 
619     private void createOutputDir() {
620         String path = null;
621         if (isTagFile()) {
622       String tagName = tagInfo.getTagClassName();
623             path = tagName.replace('.', '/');
624       path = path.substring(0, path.lastIndexOf('/'));
625         } else {
626             path = getServletPackageName().replace('.', '/');
627   }
628 
629         try {
630             // Append servlet or tag handler path to scratch dir
631             baseUrl = options.getScratchDir().toURL();
632             String outUrlString = baseUrl.toString() + '/' + path;
633             URL outUrl = new URL(outUrlString);
634             outputDir = outUrl.getFile() + File.separator;
635             makeOutputDir();
636         } catch (Exception e) {
637             throw new IllegalStateException("No output directory: " +
638                                             e.getMessage());
639         }
640     }
641     
642     private static final boolean isPathSeparator(char c) {
643        return (c == '/' || c == '\\');
644     }
645 
646     private static final String canonicalURI(String s) {
647        if (s == null) return null;
648        StringBuffer result = new StringBuffer();
649        final int len = s.length();
650        int pos = 0;
651        while (pos < len) {
652            char c = s.charAt(pos);
653            if ( isPathSeparator(c) ) {
654                /*
655                 * multiple path separators.
656                 * 'foo///bar' -> 'foo/bar'
657                 */
658                while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) {
659                    ++pos;
660                }
661 
662                if (pos+1 < len && s.charAt(pos+1) == '.') {
663                    /*
664                     * a single dot at the end of the path - we are done.
665                     */
666                    if (pos+2 >= len) break;
667 
668                    switch (s.charAt(pos+2)) {
669                        /*
670                         * self directory in path
671                         * foo/./bar -> foo/bar
672                         */
673                    case '/':
674                    case '\\':
675                        pos += 2;
676                        continue;
677 
678                        /*
679                         * two dots in a path: go back one hierarchy.
680                         * foo/bar/../baz -> foo/baz
681                         */
682                    case '.':
683                        // only if we have exactly _two_ dots.
684                        if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) {
685                            pos += 3;
686                            int separatorPos = result.length()-1;
687                            while (separatorPos >= 0 && 
688                                   ! isPathSeparator(result
689                                                     .charAt(separatorPos))) {
690                                --separatorPos;
691                            }
692                            if (separatorPos >= 0)
693                                result.setLength(separatorPos);
694                            continue;
695                        }
696                    }
697                }
698            }
699            result.append(c);
700            ++pos;
701        }
702        return result.toString();
703     }
704 }
705