View Javadoc

1   //========================================================================
2   //$Id: TagLibConfiguration.java,v 1.4 2005/08/13 00:01:27 gregwilkins Exp $
3   //Copyright 2004 Mort Bay Consulting Pty. Ltd.
4   //------------------------------------------------------------------------
5   //Licensed under the Apache License, Version 2.0 (the "License");
6   //you may not use this file except in compliance with the License.
7   //You may obtain a copy of the License at 
8   //http://www.apache.org/licenses/LICENSE-2.0
9   //Unless required by applicable law or agreed to in writing, software
10  //distributed under the License is distributed on an "AS IS" BASIS,
11  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  //See the License for the specific language governing permissions and
13  //limitations under the License.
14  //========================================================================
15  
16  package org.mortbay.jetty.webapp;
17  
18  import java.io.File;
19  import java.net.URL;
20  import java.net.URLClassLoader;
21  import java.util.Enumeration;
22  import java.util.EventListener;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.Set;
26  import java.util.jar.JarFile;
27  import java.util.regex.Pattern;
28  import java.util.zip.ZipEntry;
29  
30  import org.mortbay.log.Log;
31  import org.mortbay.resource.Resource;
32  import org.mortbay.util.Loader;
33  import org.mortbay.xml.XmlParser;
34  
35  /* ------------------------------------------------------------ */
36  /** TagLibConfiguration.
37   * 
38   * The class searches for TLD descriptors found in web.xml, in WEB-INF/*.tld files of the web app
39   * or *.tld files withing jars found in WEB-INF/lib of the webapp.   Any listeners defined in these
40   * tld's are added to the context.
41   * 
42   * <bile>This is total rubbish special case for JSPs! If there was a general use-case for web app
43   * frameworks to register listeners directly, then a generic mechanism could have been added to the servlet
44   * spec.  Instead some special purpose JSP support is required that breaks all sorts of encapsualtion rules as
45   * the servlet container must go searching for and then parsing the descriptors for one particular framework.
46   * It only appears to be used by JSF, which is being developed by the same developer who implemented this
47   * feature in the first place!
48   * </bile>
49   * 
50   * @author gregw
51   *
52   */
53  public class TagLibConfiguration implements Configuration
54  {
55      WebAppContext _context;
56      
57      /* ------------------------------------------------------------ */
58      public void setWebAppContext(WebAppContext context)
59      {
60          _context=context;
61      }
62  
63      /* ------------------------------------------------------------ */
64      public WebAppContext getWebAppContext()
65      {
66          return _context;
67      }
68  
69      /* ------------------------------------------------------------ */
70      public void configureClassLoader() throws Exception
71      {
72      }
73  
74      /* ------------------------------------------------------------ */
75      /* 
76       * @see org.mortbay.jetty.servlet.WebAppContext.Configuration#configureDefaults()
77       */
78      public void configureDefaults() throws Exception
79      {
80      }
81  
82      
83      /* ------------------------------------------------------------ */
84      /* 
85       * @see org.mortbay.jetty.servlet.WebAppContext.Configuration#configureWebApp()
86       */
87      public void configureWebApp() throws Exception
88      {   
89          Set tlds = new HashSet();
90          Set jars = new HashSet();
91          
92          // Find tld's from web.xml
93          // When the XMLConfigurator (or other configurator) parsed the web.xml,
94          // It should have created aliases for all TLDs.  So search resources aliases
95          // for aliases ending in tld
96          if (_context.getResourceAliases()!=null && 
97              _context.getBaseResource()!=null && 
98              _context.getBaseResource().exists())
99          {
100             Iterator iter=_context.getResourceAliases().values().iterator();
101             while(iter.hasNext())
102             {
103                 String location = (String)iter.next();
104                 if (location!=null && location.toLowerCase().endsWith(".tld"))
105                 {
106                     if (!location.startsWith("/"))
107                         location="/WEB-INF/"+location;
108                     Resource l=_context.getBaseResource().addPath(location);
109                     tlds.add(l);
110                 }
111             }
112         }
113         
114         // Look for any tlds in WEB-INF directly.
115         Resource web_inf = _context.getWebInf();
116         if (web_inf!=null)
117         {
118             String[] contents = web_inf.list();
119             for (int i=0;contents!=null && i<contents.length;i++)
120             {
121                 if (contents[i]!=null && contents[i].toLowerCase().endsWith(".tld"))
122                 {
123                     Resource l=_context.getWebInf().addPath(contents[i]);
124                     tlds.add(l);
125                 }
126                 
127             }
128         }
129         
130         // Get the pattern for noTLDJars
131         String no_TLD_attr = _context.getInitParameter("org.mortbay.jetty.webapp.NoTLDJarPattern");
132         Pattern no_TLD_pattern = no_TLD_attr==null?null:Pattern.compile(no_TLD_attr);
133         
134         // Look for tlds in any jars
135  
136         ClassLoader loader = Thread.currentThread().getContextClassLoader();
137         boolean parent=false;
138         
139         while (loader!=null)
140         {
141             if (loader instanceof URLClassLoader)
142             {
143                 URL[] urls = ((URLClassLoader)loader).getURLs();
144 
145                 if (urls!=null)
146                 {
147                     for (int i=0;i<urls.length;i++)
148                     {   
149                         if (urls[i].toString().toLowerCase().endsWith(".jar"))
150                         {
151 
152                             String jar = urls[i].toString();
153                             int slash=jar.lastIndexOf('/');
154                             jar=jar.substring(slash+1);
155 
156                             if (parent && ( 
157                                     (!_context.isParentLoaderPriority() && jars.contains(jar)) || 
158                                     (no_TLD_pattern!=null && no_TLD_pattern.matcher(jar).matches())))
159                                 continue;
160                             jars.add(jar);
161                             
162                             Log.debug("TLD search of {}",urls[i]);
163                             
164                             File file=Resource.newResource(urls[i]).getFile();
165                             if (file==null || !file.exists() || !file.canRead())
166                                 continue;
167                             
168                             JarFile jarfile = new JarFile(file);
169                             try
170                             {
171                                 Enumeration e = jarfile.entries();
172                                 while (e.hasMoreElements())
173                                 {
174                                     ZipEntry entry = (ZipEntry)e.nextElement();
175                                     String name = entry.getName();
176                                     if (name.startsWith("META-INF/") && name.toLowerCase().endsWith(".tld"))
177                                     {
178                                         Resource tld=Resource.newResource("jar:"+urls[i]+"!/"+name);
179                                         tlds.add(tld);
180                                         Log.debug("TLD found {}",tld);
181                                     }
182                                 }
183                             }
184                             finally
185                             {
186                                 jarfile.close();
187                             }   
188                         }
189                     }
190                 }
191             }
192 
193             loader=loader.getParent();
194             parent=true;
195             
196         }
197         
198         // Create a TLD parser
199         XmlParser parser = new XmlParser(false);
200         parser.redirectEntity("web-jsptaglib_1_1.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd", false));
201         parser.redirectEntity("web-jsptaglib_1_2.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd", false));
202         parser.redirectEntity("web-jsptaglib_2_0.xsd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd", false));
203         parser.redirectEntity("web-jsptaglibrary_1_1.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd", false));
204         parser.redirectEntity("web-jsptaglibrary_1_2.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd", false));
205         parser.redirectEntity("web-jsptaglibrary_2_0.xsd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd", false));
206         parser.setXpath("/taglib/listener/listener-class");
207         // Parse all the discovered TLDs
208         Iterator iter = tlds.iterator();
209         while (iter.hasNext())
210         {
211             try
212             {
213                 Resource tld = (Resource)iter.next();
214                 if (Log.isDebugEnabled()) Log.debug("TLD="+tld);
215                 
216                 XmlParser.Node root;
217                 
218                 try
219                 {
220                     //xerces on apple appears to sometimes close the zip file instead
221                     //of the inputstream, so try opening the input stream, but if
222                     //that doesn't work, fallback to opening a new url
223                     root = parser.parse(tld.getInputStream());
224                 }
225                 catch (Exception e)
226                 {
227                     root = parser.parse(tld.getURL().toString());
228                 }
229 
230 		if (root==null)
231 		{
232 		    Log.warn("No TLD root in {}",tld);
233 		    continue;
234 		}
235                 
236                 for (int i=0;i<root.size();i++)
237                 {
238                     Object o=root.get(i);
239                     if (o instanceof XmlParser.Node)
240                     {
241                         XmlParser.Node node = (XmlParser.Node)o;
242                         if ("listener".equals(node.getTag()))
243                         {
244                             String className=node.getString("listener-class",false,true);
245                             if (Log.isDebugEnabled()) Log.debug("listener="+className);
246                             
247                             try
248                             {
249                                 Class listenerClass=getWebAppContext().loadClass(className);
250                                 EventListener l=(EventListener)listenerClass.newInstance();
251                                 _context.addEventListener(l);
252                             }
253                             catch(Exception e)
254                             {
255                                 Log.warn("Could not instantiate listener "+className+": "+e);
256                                 Log.debug(e);
257                             }
258                             catch(Error e)
259                             {
260                                 Log.warn("Could not instantiate listener "+className+": "+e);
261                                 Log.debug(e);
262                             }
263                         }
264                     }
265                 }
266             }
267             catch(Exception e)
268             {
269                 Log.warn(e);
270             }
271         }
272     }
273 
274 
275     public void deconfigureWebApp() throws Exception
276     {
277     }
278     
279 
280 }