View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.webapp;
15  
16  import java.net.URL;
17  import java.util.ArrayList;
18  import java.util.Collection;
19  import java.util.EventListener;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Set;
24  import java.util.jar.JarEntry;
25  import java.util.regex.Pattern;
26  
27  import javax.servlet.Servlet;
28  
29  import org.eclipse.jetty.util.Loader;
30  import org.eclipse.jetty.util.log.Log;
31  import org.eclipse.jetty.util.resource.Resource;
32  import org.eclipse.jetty.xml.XmlParser;
33  
34  /* ------------------------------------------------------------ */
35  /** TagLibConfiguration.
36   * 
37   * The class searches for TLD descriptors found in web.xml, in WEB-INF/*.tld files of the web app
38   * or *.tld files within jars found in WEB-INF/lib of the webapp.   Any listeners defined in these
39   * tld's are added to the context.
40   * 
41   * <bile>This is total rubbish special case for JSPs! If there was a general use-case for web app
42   * frameworks to register listeners directly, then a generic mechanism could have been added to the servlet
43   * spec.  Instead some special purpose JSP support is required that breaks all sorts of encapsulation rules as
44   * the servlet container must go searching for and then parsing the descriptors for one particular framework.
45   * It only appears to be used by JSF, which is being developed by the same developer who implemented this
46   * feature in the first place!
47   * </bile>
48   * 
49   * 
50   *
51   */
52  public class TagLibConfiguration implements Configuration
53  {
54      public static final String TLD_RESOURCES = "org.eclipse.jetty.tlds";
55      
56      // TODO support patterns
57      private static final String __web_inf_pattern = "org.eclipse.jetty.webapp.WebInfIncludeTLDJarPattern";
58      private static final String __container_pattern = "org.eclipse.jetty.server.webapp.ContainerIncludeTLDJarPattern";
59      
60      public class TldProcessor
61      {
62          public static final String __taglib_processor = "org.eclipse.jetty.tagLibProcessor";
63          XmlParser _parser;
64          WebAppContext _context;
65          List<XmlParser.Node> _roots = new ArrayList<XmlParser.Node>();
66          
67          
68          public TldProcessor (WebAppContext context)
69          throws Exception
70          {
71              _context = context;
72              createParser();
73          }
74          
75          private void createParser ()
76          throws Exception
77          {
78              // Create a TLD parser
79              _parser = new XmlParser(false);
80              
81              URL taglib11=null;
82              URL taglib12=null;
83              URL taglib20=null;
84              URL taglib21=null;
85  
86              try
87              {
88                  Class jsp_page = Loader.loadClass(WebXmlConfiguration.class,"javax.servlet.jsp.JspPage");
89                  taglib11=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd");
90                  taglib12=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd");
91                  taglib20=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd");
92                  taglib21=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd");
93              }
94              catch(Exception e)
95              {
96                  Log.ignore(e);
97              }
98              finally
99              {
100                 if(taglib11==null)
101                     taglib11=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd",true);
102                 if(taglib12==null)
103                     taglib12=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd",true);
104                 if(taglib20==null)
105                     taglib20=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd",true);
106                 if(taglib21==null)
107                     taglib21=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd",true);
108             }
109             
110 
111             if(taglib11!=null)
112             {
113                 _parser.redirectEntity("web-jsptaglib_1_1.dtd",taglib11);
114                 _parser.redirectEntity("web-jsptaglibrary_1_1.dtd",taglib11);
115             }
116             if(taglib12!=null)
117             {
118                 _parser.redirectEntity("web-jsptaglib_1_2.dtd",taglib12);
119                 _parser.redirectEntity("web-jsptaglibrary_1_2.dtd",taglib12);
120             }
121             if(taglib20!=null)
122             {
123                 _parser.redirectEntity("web-jsptaglib_2_0.xsd",taglib20);
124                 _parser.redirectEntity("web-jsptaglibrary_2_0.xsd",taglib20);
125             }
126             if(taglib21!=null)
127             {
128                 _parser.redirectEntity("web-jsptaglib_2_1.xsd",taglib21);
129                 _parser.redirectEntity("web-jsptaglibrary_2_1.xsd",taglib21);
130             }
131             
132             _parser.setXpath("/taglib/listener/listener-class");
133         }
134         
135         
136         public XmlParser.Node parse (Resource tld)
137         throws Exception
138         {
139             XmlParser.Node root;
140             try
141             {
142                 //xerces on apple appears to sometimes close the zip file instead
143                 //of the inputstream, so try opening the input stream, but if
144                 //that doesn't work, fallback to opening a new url
145                 root = _parser.parse(tld.getInputStream());
146             }
147             catch (Exception e)
148             {
149                 root = _parser.parse(tld.getURL().toString());
150             }
151 
152             if (root==null)
153             {
154                 Log.warn("No TLD root in {}",tld);
155             }
156             else
157                 _roots.add(root);
158             
159             return root;
160         }
161         
162         public void processRoots ()
163         {
164             for (XmlParser.Node root: _roots)
165                 process(root);
166         }
167         
168         public void process (XmlParser.Node root)
169         {     
170             for (int i=0;i<root.size();i++)
171             {
172                 Object o=root.get(i);
173                 if (o instanceof XmlParser.Node)
174                 {
175                     XmlParser.Node node = (XmlParser.Node)o;
176                     if ("listener".equals(node.getTag()))
177                     {
178                         String className=node.getString("listener-class",false,true);
179                         if (Log.isDebugEnabled()) Log.debug("listener="+className);
180                         
181                         try
182                         {
183                             Class listenerClass = _context.loadClass(className);
184                             EventListener l = (EventListener)listenerClass.newInstance();
185                             _context.addEventListener(l);
186                         }
187                         catch(Exception e)
188                         {
189                             Log.warn("Could not instantiate listener "+className+": "+e);
190                             Log.debug(e);
191                         }
192                         catch(Error e)
193                         {
194                             Log.warn("Could not instantiate listener "+className+": "+e);
195                             Log.debug(e);
196                         }
197                     }
198                 }
199             }
200         }
201         
202     }
203 
204 
205     public void preConfigure(WebAppContext context) throws Exception
206     {
207         Set tlds = new HashSet();
208 
209         // Find tld's from web.xml
210         // When web.xml was processed, it should have created aliases for all TLDs.  So search resources aliases
211         // for aliases ending in tld
212         if (context.getResourceAliases()!=null && 
213                 context.getBaseResource()!=null && 
214                 context.getBaseResource().exists())
215         {
216             Iterator iter=context.getResourceAliases().values().iterator();
217             while(iter.hasNext())
218             {
219                 String location = (String)iter.next();
220                 if (location!=null && location.toLowerCase().endsWith(".tld"))
221                 {
222                     if (!location.startsWith("/"))
223                         location="/WEB-INF/"+location;
224                     Resource l=context.getBaseResource().addPath(location);
225                     tlds.add(l);
226                 }
227             }
228         }
229         
230         // Look for any tlds in WEB-INF directly.
231         Resource web_inf = context.getWebInf();
232         if (web_inf!=null)
233         {
234             String[] contents = web_inf.list();
235             for (int i=0;contents!=null && i<contents.length;i++)
236             {
237                 if (contents[i]!=null && contents[i].toLowerCase().endsWith(".tld"))
238                 {
239                     Resource l=context.getWebInf().addPath(contents[i]);
240                     tlds.add(l);
241                 }
242             }
243         }
244         
245     
246         // Add in tlds found in META-INF of jars
247         Collection<Resource> tld_resources=(Collection<Resource>)context.getAttribute(TLD_RESOURCES);
248         if (tld_resources!=null)
249             tlds.addAll(tld_resources);
250         
251         // Create a processor for the tlds and save it
252         TldProcessor processor = new TldProcessor (context);
253         context.setAttribute(TldProcessor.__taglib_processor, processor);
254         // Parse the tlds into memory
255         Iterator iter = tlds.iterator();
256         while (iter.hasNext())
257         {
258             try
259             {
260                 Resource tld = (Resource)iter.next();
261                 if (Log.isDebugEnabled()) Log.debug("TLD="+tld);
262                 processor.parse(tld);
263             }
264             catch(Exception e)
265             {
266                 Log.warn(e);
267             }
268         }
269     }
270     
271 
272     public void configure (WebAppContext context) throws Exception
273     {         
274         TldProcessor processor = (TldProcessor)context.getAttribute(TldProcessor.__taglib_processor); 
275         if (processor == null)
276         {
277             Log.warn("No TldProcessor configured, skipping tld processing");
278             return;
279         }
280 
281         //Create listeners from the parsed tld trees
282         processor.processRoots();
283     }
284 
285     public void postConfigure(WebAppContext context) throws Exception
286     {
287         // TODO Auto-generated method stub
288         
289     }
290 
291     public void deconfigure(WebAppContext context) throws Exception
292     {
293         // TODO Auto-generated method stub
294         
295     }
296 
297 }