KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > jsp > TldManager


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.jsp;
31
32 import com.caucho.config.Config;
33 import com.caucho.config.ConfigException;
34 import com.caucho.config.types.FileSetType;
35 import com.caucho.jsp.cfg.JspPropertyGroup;
36 import com.caucho.jsp.cfg.TldPreload;
37 import com.caucho.jsp.cfg.TldTaglib;
38 import com.caucho.loader.DynamicClassLoader;
39 import com.caucho.loader.EnvironmentLocal;
40 import com.caucho.log.Log;
41 import com.caucho.server.util.CauchoSystem;
42 import com.caucho.server.webapp.WebApp;
43 import com.caucho.util.Alarm;
44 import com.caucho.util.L10N;
45 import com.caucho.vfs.JarPath;
46 import com.caucho.vfs.MergePath;
47 import com.caucho.vfs.Path;
48 import com.caucho.vfs.ReadStream;
49 import com.caucho.vfs.Vfs;
50
51 import java.io.IOException JavaDoc;
52 import java.io.InputStream JavaDoc;
53 import java.lang.ref.SoftReference JavaDoc;
54 import java.util.ArrayList JavaDoc;
55 import java.util.Enumeration JavaDoc;
56 import java.util.HashMap JavaDoc;
57 import java.util.jar.JarFile JavaDoc;
58 import java.util.logging.Level JavaDoc;
59 import java.util.logging.Logger JavaDoc;
60 import java.util.zip.ZipEntry JavaDoc;
61 import java.util.zip.ZipFile JavaDoc;
62
63 /**
64  * Stores the parsed tlds.
65  */

66 public class TldManager {
67   static final L10N L = new L10N(TldManager.class);
68   private static final Logger JavaDoc log = Log.open(TldManager.class);
69
70   private static ArrayList JavaDoc<TldPreload> _cauchoTaglibs;
71   private static ArrayList JavaDoc<TldPreload> _globalTaglibs;
72   private static ArrayList JavaDoc<Path> _globalPaths;
73   
74   private static EnvironmentLocal<TldManager> _localManager
75     = new EnvironmentLocal<TldManager>();
76   
77   private JspResourceManager _resourceManager;
78   private WebApp _webApp;
79   
80   private HashMap JavaDoc<Path,SoftReference JavaDoc<TldTaglib>> _tldMap
81     = new HashMap JavaDoc<Path,SoftReference JavaDoc<TldTaglib>>();
82   
83   private JspParseException _loadAllTldException;
84   private String JavaDoc _tldDir;
85   private FileSetType _tldFileSet;
86
87   private volatile boolean _isInit;
88
89   private Config _config = new Config();
90   private ArrayList JavaDoc<TldPreload> _preloadTaglibs;
91
92   private TldManager(JspResourceManager resourceManager,
93              WebApp app)
94     throws JspParseException, IOException JavaDoc
95   {
96     _resourceManager = resourceManager;
97     _webApp = app;
98
99     if (app != null) {
100       JspPropertyGroup jsp = app.getJsp();
101       if (jsp != null)
102     _tldFileSet = jsp.getTldFileSet();
103     }
104
105     // JSF has a global listener hidden in one of the *.tld which
106
// requires Resin to search all the JSPs.
107
initGlobal();
108   }
109
110   static TldManager create(JspResourceManager resourceManager,
111                WebApp app)
112     throws JspParseException, IOException JavaDoc
113   {
114     
115     TldManager manager = null;
116     
117     synchronized (_localManager) {
118       manager = _localManager.getLevel();
119
120       if (manager != null)
121     return manager;
122       
123       manager = new TldManager(resourceManager, app);
124       _localManager.set(manager);
125     }
126
127     return manager;
128   }
129
130   /**
131    * Sets the webApp.
132    */

133   void setWebApp(WebApp webApp)
134   {
135     _webApp = webApp;
136   }
137
138   public String JavaDoc getSchema()
139   {
140     return "com/caucho/jsp/cfg/jsp-tld.rnc";
141   }
142     
143   public void setTldDir(String JavaDoc tldDir)
144   {
145     _tldDir = tldDir;
146   }
147     
148   public void setTldFileSet(FileSetType tldFileSet)
149   {
150     _tldFileSet = tldFileSet;
151   }
152
153   /**
154    * Loads all the .tld files in the WEB-INF and the META-INF for
155    * the entire classpath.
156    */

157   public synchronized void init()
158     throws JspParseException, IOException JavaDoc
159   {
160     if (_isInit)
161       return;
162     _isInit = true;
163
164     log.fine("Loading .tld files");
165     
166     String JavaDoc dir;
167
168     if (_tldDir == null)
169       dir = "WEB-INF";
170     else if (_tldDir.startsWith("/"))
171       dir = _tldDir.substring(1);
172     else if (_tldDir.startsWith("WEB-INF"))
173       dir = _tldDir;
174     else
175       dir = "WEB-INF/" + _tldDir;
176       
177     FileSetType fileSet = _tldFileSet;
178     if (fileSet == null) {
179       fileSet = new FileSetType();
180       fileSet.setDir(_resourceManager.resolvePath(dir));
181       try {
182     fileSet.init();
183       } catch (Exception JavaDoc e) {
184     log.config(e.toString());
185       }
186     }
187       
188     ArrayList JavaDoc<TldPreload> taglibs = new ArrayList JavaDoc<TldPreload>();
189     
190     taglibs.addAll(_globalTaglibs);
191
192     MergePath classPath = new MergePath();
193     classPath.addClassPath();
194
195     ArrayList JavaDoc<Path> paths = classPath.getMergePaths();
196
197     for (int i = 0; i < paths.size(); i++) {
198       Path subPath = paths.get(i);
199
200       if (_globalPaths.contains(subPath))
201     continue;
202
203       if (subPath instanceof JarPath)
204     loadJarTlds(taglibs, (JarPath) subPath, "META-INF");
205       else
206     loadAllTlds(taglibs, subPath.lookup("META-INF"), 64, "META-INF");
207     }
208     
209     if (fileSet != null)
210       loadAllTlds(taglibs, fileSet);
211
212     /*
213     for (int i = 0; i < taglibs.size(); i++) {
214       TldTaglib taglib = taglibs.get(i);
215
216       if (taglib.getConfigException() != null &&
217       taglib.getURI() == null) {
218     _loadAllTldException = JspParseException.create(taglib.getConfigException());
219       }
220     }
221     */

222     taglibs.addAll(_cauchoTaglibs);
223
224     _preloadTaglibs = taglibs;
225
226     for (int i = 0; i < taglibs.size(); i++) {
227       try {
228     taglibs.get(i).initListeners(_webApp);
229       } catch (Exception JavaDoc e) {
230     throw new JspParseException(e);
231       }
232     }
233   }
234
235   public synchronized void initGlobal()
236   {
237     // loads tag libraries from the global context (so there's no
238
// need to reparse the jars for each web-app
239
if (_globalTaglibs == null) {
240       if (! Alarm.isTest()) {
241     log.info("Loading .tld files from global classpath");
242       }
243       
244       ArrayList JavaDoc<TldPreload> globalTaglibs = new ArrayList JavaDoc<TldPreload>();
245       ArrayList JavaDoc<TldPreload> cauchoTaglibs = new ArrayList JavaDoc<TldPreload>();
246
247       Thread JavaDoc thread = Thread.currentThread();
248       ClassLoader JavaDoc oldLoader = thread.getContextClassLoader();
249       thread.setContextClassLoader(TldManager.class.getClassLoader());
250       try {
251     MergePath globalClassPath = new MergePath();
252     globalClassPath.addClassPath();
253     
254     ArrayList JavaDoc<Path> paths = globalClassPath.getMergePaths();
255     _globalPaths = paths;
256
257     loadClassPathTlds(globalTaglibs, paths, "");
258
259     for (int i = globalTaglibs.size() - 1; i >= 0; i--) {
260       TldPreload tld = globalTaglibs.get(i);
261
262       if (tld.getPath() == null || tld.getPath().getPath() == null)
263         continue;
264       
265       String JavaDoc tldPathName = tld.getPath().getPath();
266
267       if (tldPathName.startsWith("/com/caucho")) {
268         cauchoTaglibs.add(globalTaglibs.remove(i));
269       }
270     }
271       } catch (Exception JavaDoc e) {
272     log.log(Level.WARNING, e.toString(), e);
273       } finally {
274     thread.setContextClassLoader(oldLoader);
275       }
276
277       _globalTaglibs = globalTaglibs;
278       _cauchoTaglibs = cauchoTaglibs;
279     }
280   }
281
282   private void loadClassPathTlds(ArrayList JavaDoc<TldPreload> taglibs,
283                  ArrayList JavaDoc<Path> paths,
284                  String JavaDoc prefix)
285     throws JspParseException, IOException JavaDoc
286   {
287     for (int i = 0; i < paths.size(); i++) {
288       Path subPath = paths.get(i);
289
290       if (subPath instanceof JarPath)
291     loadJarTlds(taglibs, (JarPath) subPath, prefix);
292       else if (prefix != null && ! prefix.equals(""))
293     loadAllTlds(taglibs, subPath.lookup(prefix), 64, prefix);
294       else
295     loadAllTlds(taglibs, subPath.lookup("META-INF"), 64, "META-INF");
296     }
297   }
298
299   /*
300   ArrayList<TldTaglib> getTaglibs()
301   {
302     return new ArrayList<TldTaglib>(_preloadTaglibs);
303   }
304   */

305
306   private void loadAllTlds(ArrayList JavaDoc<TldPreload> taglibs,
307                FileSetType fileSet)
308     throws JspParseException, IOException JavaDoc
309   {
310     for (Path path : fileSet.getPaths()) {
311       if (path.getPath().startsWith(".")) {
312       }
313       else if (path.getPath().endsWith(".tld") &&
314            path.isFile() && path.canRead()) {
315     try {
316       TldPreload taglib = parseTldPreload(path);
317
318       taglibs.add(taglib);
319
320       if (taglib.getURI() == null &&
321           taglib.getConfigException() != null &&
322           _loadAllTldException == null)
323         _loadAllTldException = new JspLineParseException(taglib.getConfigException());
324     } catch (Throwable JavaDoc e) {
325       log.warning(e.getMessage());
326     }
327       }
328     }
329   }
330   
331   private void loadAllTlds(ArrayList JavaDoc<TldPreload> taglibs,
332                Path path, int depth, String JavaDoc userPath)
333     throws JspParseException, IOException JavaDoc
334   {
335     if (depth < 0)
336       throw new JspParseException(L.l("max depth exceeded while reading .tld files. Probable loop in filesystem detected at `{0}'.", path));
337
338     path.setUserPath(userPath);
339     
340     if (path.getPath().startsWith(".")) {
341     }
342     else if (path.getPath().endsWith(".tld") &&
343              path.isFile() && path.canRead()) {
344       try {
345     TldPreload taglib = parseTldPreload(path);
346
347     taglibs.add(taglib);
348
349     if (taglib.getURI() == null &&
350         taglib.getConfigException() != null &&
351         _loadAllTldException == null)
352       _loadAllTldException = new JspLineParseException(taglib.getConfigException());
353       } catch (Throwable JavaDoc e) {
354     /*
355     if (_loadAllTldException == null) {
356     }
357     else if (e instanceof JspParseException)
358       _loadAllTldException = (JspParseException) e;
359     else
360       _loadAllTldException = new JspParseException(e);
361     */

362     
363     log.warning(e.getMessage());
364       }
365     }
366     else if (path.isDirectory()) {
367       String JavaDoc []fileNames = path.list();
368       
369       for (int i = 0; fileNames != null && i < fileNames.length; i++) {
370         String JavaDoc name = fileNames[i];
371
372         ArrayList JavaDoc<Path> resources = path.getResources(name);
373
374         for (int j = 0; resources != null && j < resources.size(); j++) {
375           Path subpath = resources.get(j);
376
377           loadAllTlds(taglibs, subpath, depth - 1, userPath + "/" + name);
378         }
379       }
380     }
381   }
382
383   private void loadJarTlds(ArrayList JavaDoc<TldPreload> taglibs,
384                JarPath jar,
385                String JavaDoc prefix)
386     throws JspParseException, IOException JavaDoc
387   {
388     if (! jar.getContainer().canRead())
389       return;
390     
391     String JavaDoc nativePath = jar.getContainer().getNativePath();
392     ZipFile JavaDoc zipFile;
393
394     if (nativePath.endsWith(".jar"))
395       zipFile = new JarFile JavaDoc(nativePath);
396     else
397       zipFile = new ZipFile JavaDoc(nativePath);
398
399     try {
400       Enumeration JavaDoc<? extends ZipEntry JavaDoc> en = zipFile.entries();
401       while (en.hasMoreElements()) {
402     ZipEntry JavaDoc entry = en.nextElement();
403     String JavaDoc name = entry.getName();
404
405     if (name.startsWith(prefix) && name.endsWith(".tld")) {
406       Path path = jar.lookup(name);
407
408       try {
409         TldPreload taglib = parseTldPreload(path);
410
411         taglibs.add(taglib);
412
413         if (taglib.getURI() == null &&
414         taglib.getConfigException() != null &&
415         _loadAllTldException == null)
416           _loadAllTldException = new JspLineParseException(taglib.getConfigException());
417       } catch (Throwable JavaDoc e) {
418         /*
419           if (_loadAllTldException == null) {
420           }
421           else if (e instanceof JspParseException)
422           _loadAllTldException = (JspParseException) e;
423           else
424           _loadAllTldException = new JspParseException(e);
425         */

426     
427         log.warning(e.getMessage());
428       }
429     }
430       }
431     } finally {
432       zipFile.close();
433     }
434   }
435
436   /**
437    * Returns the tld parsed at the given location.
438    */

439   TldTaglib parseTld(String JavaDoc uri, String JavaDoc mapLocation, String JavaDoc location)
440     throws JspParseException, IOException JavaDoc
441   {
442     init();
443     
444     for (int i = 0; i < _preloadTaglibs.size(); i++) {
445       TldPreload preload = _preloadTaglibs.get(i);
446
447       if (uri.equals(preload.getURI())
448       && (mapLocation == null
449           || mapLocation.equals(preload.getLocation())
450           || mapLocation.equals(uri))) {
451     return parseTld(preload.getPath());
452       }
453     }
454
455     return parseTld(location);
456   }
457        
458   /**
459    * Returns the tld parsed at the given location.
460    */

461   TldTaglib parseTld(String JavaDoc location)
462     throws JspParseException, IOException JavaDoc
463   {
464     init();
465     
466     TldTaglib tld = findTld(location);
467
468     /* XXX: jsp/18n0 handled on init
469     if (tld != null) {
470       try {
471     tld.init(_webApp);
472       } catch (Exception e) {
473     throw new JspParseException(e);
474       }
475     }
476     */

477
478     return tld;
479   }
480
481   /**
482    * Returns the tld parsed at the given location.
483    */

484   private TldTaglib findTld(String JavaDoc location)
485     throws JspParseException, IOException JavaDoc
486   {
487     InputStream JavaDoc is = null;
488
489     Path path;
490
491     if (location.startsWith("file:")) {
492       path = _resourceManager.resolvePath(location);
493     }
494     else if (location.indexOf(':') >= 0 && ! location.startsWith("file:") &&
495         location.indexOf(':') < location.indexOf('/')) {
496       if (_loadAllTldException != null)
497     throw _loadAllTldException;
498       
499       return null;
500       /* XXX: jsp/0316
501       throw new JspParseException(L.l("Unknown taglib `{0}'. Taglibs specified with an absolute URI must either be:\n1) specified in the web.xml\n2) defined in a jar's .tld in META-INF\n3) defined in a .tld in WEB-INF\n4) predefined by Resin",
502                                       location));
503       */

504     }
505     else if (! location.startsWith("/"))
506       path = _resourceManager.resolvePath("WEB-INF/" + location);
507     else
508       path = _resourceManager.resolvePath("." + location);
509
510     path.setUserPath(location);
511
512     Path jar = null;
513       
514     if (location.endsWith(".jar")) {
515       path = findJar(location);
516
517       if (path != null && path.exists()) {
518         jar = JarPath.create(path);
519         if (jar.lookup("META-INF/taglib.tld").exists())
520           return parseTld(jar.lookup("META-INF/taglib.tld"));
521         else if (jar.lookup("meta-inf/taglib.tld").exists())
522           return parseTld(jar.lookup("meta-inf/taglib.tld"));
523         else
524           throw new JspParseException(L.l("can't find META-INF/taglib.tld in `{0}'",
525                                           location));
526       }
527       else {
528         throw new JspParseException(L.l("Can't find taglib `{0}'. A taglib uri ending in *.jar must point to an actual jar or match a URI in a .tld file.", location));
529       }
530     }
531     else if (path.exists() && path.canRead() && path.isFile())
532       return parseTld(path);
533
534     if (_loadAllTldException != null)
535       throw _loadAllTldException;
536     else
537       throw new JspParseException(L.l("Can't find taglib-location `{0}'. The taglib-location must match a tag library either:\n1) by pointing to a .tld directly, relative to the application's root directory\n2) specified in the web.xml\n3) defined in a jar's .tld in META-INF\n4) defined in a .tld in WEB-INF\n5) predefined by Resin",
538                                       location));
539   }
540
541   /**
542    * Parses the .tld
543    *
544    * @param is the input stream to the taglib
545    */

546   private TldTaglib parseTld(Path path)
547     throws JspParseException, IOException JavaDoc
548   {
549     SoftReference JavaDoc<TldTaglib> taglibRef = _tldMap.get(path);
550     TldTaglib taglib;
551
552     if (taglibRef != null) {
553       taglib = taglibRef.get();
554
555       if (taglib != null && ! taglib.isModified())
556     return taglib;
557     }
558     
559     ReadStream is = path.openRead();
560
561     try {
562       taglib = parseTld(is);
563
564       if (path instanceof JarPath)
565     taglib.setJarPath(path.lookup("/"));
566
567       _tldMap.put(path, new SoftReference JavaDoc<TldTaglib>(taglib));
568       
569       return taglib;
570     } finally {
571       is.close();
572     }
573   }
574
575   /**
576    * Parses the .tld
577    *
578    * @param is the input stream to the taglib
579    */

580   private TldTaglib parseTld(InputStream JavaDoc is)
581     throws JspParseException, IOException JavaDoc
582   {
583     TldTaglib taglib = new TldTaglib();
584
585     if (is instanceof ReadStream) {
586       Path path = ((ReadStream) is).getPath();
587     
588       path.setUserPath(path.getURL());
589     }
590       
591     String JavaDoc schema = null;
592
593     if (_webApp.getJsp() == null ||
594     _webApp.getJsp().isValidateTaglibSchema()) {
595       schema = getSchema();
596     }
597
598     try {
599       Config config = new Config();
600       config.setEL(false);
601       config.configure(taglib, is, schema);
602     } catch (ConfigException e) {
603       log.warning(e.toString());
604       log.log(Level.FINER, e.toString(), e);
605
606       taglib.setConfigException(e);
607     } catch (Exception JavaDoc e) {
608       log.warning(e.toString());
609       log.log(Level.FINER, e.toString(), e);
610
611       taglib.setConfigException(e);
612     } finally {
613       is.close();
614     }
615
616     /* XXX: jsp/18n0 handled on init
617     try {
618       taglib.init(_webApp);
619     } catch (Exception e) {
620       throw new JspParseException(e);
621     }
622     */

623     
624     return taglib;
625   }
626
627   /**
628    * Parses the .tld
629    *
630    * @param path location of the taglib
631    */

632   private TldPreload parseTldPreload(Path path)
633     throws JspParseException, IOException JavaDoc
634   {
635     ReadStream is = path.openRead();
636
637     try {
638       TldPreload taglib = parseTldPreload(is);
639
640       taglib.setPath(path);
641       String JavaDoc appDir = _webApp.getAppDir().getPath();
642       String JavaDoc tagPath = path.getPath();
643
644       if (tagPath.startsWith(appDir))
645     taglib.setLocation(tagPath.substring(appDir.length()));
646
647       return taglib;
648     } finally {
649       is.close();
650     }
651   }
652
653   /**
654    * Parses the .tld
655    *
656    * @param is the input stream to the taglib
657    */

658   private TldPreload parseTldPreload(InputStream JavaDoc is)
659     throws JspParseException, IOException JavaDoc
660   {
661     if (is instanceof ReadStream) {
662       Path path = ((ReadStream) is).getPath();
663     
664       path.setUserPath(path.getURL());
665     }
666       
667     String JavaDoc schema = null;
668
669     if (_webApp.getJsp() == null ||
670     _webApp.getJsp().isValidateTaglibSchema()) {
671       schema = getSchema();
672     }
673
674     TldPreload taglib = new TldPreload();
675     try {
676       _config.configure(taglib, is, schema);
677     } catch (ConfigException e) {
678       log.warning(e.toString());
679       log.log(Level.FINER, e.toString(), e);
680
681       taglib.setConfigException(e);
682     } catch (Exception JavaDoc e) {
683       log.warning(e.toString());
684       log.log(Level.FINER, e.toString(), e);
685
686       taglib.setConfigException(e);
687     } finally {
688       is.close();
689     }
690     
691     return taglib;
692   }
693
694   /**
695    * Finds the path to the jar specified by the location.
696    *
697    * @param location the tag-location specified in the web.xml
698    *
699    * @return the found jar or null
700    */

701   private Path findJar(String JavaDoc location)
702   {
703     Path path;
704
705     if (location.startsWith("file:"))
706       path = Vfs.lookup(location);
707     else if (location.startsWith("/"))
708       path = _resourceManager.resolvePath("." + location);
709     else
710       path = _resourceManager.resolvePath(location);
711
712     if (path.exists())
713       return path;
714
715     DynamicClassLoader loader;
716     loader = (DynamicClassLoader) Thread.currentThread().getContextClassLoader();
717     String JavaDoc classPath = loader.getClassPath();
718     char sep = CauchoSystem.getPathSeparatorChar();
719
720     int head = 0;
721     int tail = 0;
722     
723     while ((tail = classPath.indexOf(sep, head)) >= 0) {
724       String JavaDoc sub = classPath.substring(head, tail);
725
726       path = Vfs.lookup(sub);
727       
728       if (sub.endsWith(location) && path.exists())
729         return path;
730
731       head = tail + 1;
732     }
733
734     if (classPath.length() <= head)
735       return null;
736     
737     String JavaDoc sub = classPath.substring(head);
738
739     path = Vfs.lookup(sub);
740       
741     if (sub.endsWith(location) && path.exists())
742       return path;
743     else
744       return null;
745   }
746 }
747
Popular Tags