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   * The "org.mortbay.jetty.webapp.NoTLDJarPattern" context init parameter, if set, is used as a
    43   * regular expression to match commonly known jar files known not to contain TLD files (and
    44   * thus not needed to be scanned).
    45   *
    46   * &lt;bile&gt;Scanning for TLDs is total rubbish special case for JSPs! If there was a general use-case for web app
    47   * frameworks to register listeners directly, then a generic mechanism could have been added to the servlet
    48   * spec.  Instead some special purpose JSP support is required that breaks all sorts of encapsualtion rules as
    49   * the servlet container must go searching for and then parsing the descriptors for one particular framework.
    50   * It only appears to be used by JSF.
    51   * &lt;/bile&gt;
    52   *
    53   * @author gregw
    54   *
    55   */
    56  public class TagLibConfiguration implements Configuration
    57  {
    58      WebAppContext _context;
    59
    60      /* ------------------------------------------------------------ */
    61      public void setWebAppContext(WebAppContext context)
    62      {
    63          _context=context;
    64      }
    65
    66      /* ------------------------------------------------------------ */
    67      public WebAppContext getWebAppContext()
    68      {
    69          return _context;
    70      }
    71
    72      /* ------------------------------------------------------------ */
    73      public void configureClassLoader() throws Exception
    74      {
    75      }
    76
    77      /* ------------------------------------------------------------ */
    78      /*
    79       * @see org.mortbay.jetty.servlet.WebAppContext.Configuration#configureDefaults()
    80       */
    81      public void configureDefaults() throws Exception
    82      {
    83      }
    84
    85
    86      /* ------------------------------------------------------------ */
    87      /*
    88       * @see org.mortbay.jetty.servlet.WebAppContext.Configuration#configureWebApp()
    89       */
    90      public void configureWebApp() throws Exception
    91      {
    92          Set tlds = new HashSet();
    93          Set jars = new HashSet();
    94
    95          // Find tld's from web.xml
    96          // When the XMLConfigurator (or other configurator) parsed the web.xml,
    97          // It should have created aliases for all TLDs.  So search resources aliases
    98          // for aliases ending in tld
    99          if (_context.getResourceAliases()!=null &&
    100             _context.getBaseResource()!=null &&
    101             _context.getBaseResource().exists())
    102         {
    103             Iterator iter=_context.getResourceAliases().values().iterator();
    104             while(iter.hasNext())
    105             {
    106                 String location = (String)iter.next();
    107                 if (location!=null && location.toLowerCase().endsWith(".tld"))
    108                 {
    109                     if (!location.startsWith("/"))
    110                         location="/WEB-INF/"+location;
    111                     Resource l=_context.getBaseResource().addPath(location);
    112                     tlds.add(l);
    113                 }
    114             }
    115         }
    116
    117         // Look for any tlds in WEB-INF directly.
    118         Resource web_inf = _context.getWebInf();
    119         if (web_inf!=null)
    120         {
    121             String[] contents = web_inf.list();
    122             for (int i=0;contents!=null && i<contents.length;i++)
    123             {
    124                 if (contents[i]!=null && contents[i].toLowerCase().endsWith(".tld"))
    125                 {
    126                     Resource l=_context.getWebInf().addPath(contents[i]);
    127                     tlds.add(l);
    128                 }
    129
    130             }
    131         }
    132
    133         // Get the pattern for noTLDJars
    134         String no_TLD_attr = _context.getInitParameter("org.mortbay.jetty.webapp.NoTLDJarPattern");
    135         Pattern no_TLD_pattern = no_TLD_attr==null?null:Pattern.compile(no_TLD_attr);
    136
    137         // Look for tlds in any jars
    138
    139         ClassLoader loader = Thread.currentThread().getContextClassLoader();
    140         boolean parent=false;
    141
    142         while (loader!=null)
    143         {
    144             if (loader instanceof URLClassLoader)
    145             {
    146                 URL[] urls = ((URLClassLoader)loader).getURLs();
    147
    148                 if (urls!=null)
    149                 {
    150                     for (int i=0;i<urls.length;i++)
    151                     {
    152                         if (urls[i].toString().toLowerCase().endsWith(".jar"))
    153                         {
    154
    155                             String jar = urls[i].toString();
    156                             int slash=jar.lastIndexOf('/');
    157                             jar=jar.substring(slash+1);
    158
    159                             if (parent && (
    160                                     (!_context.isParentLoaderPriority() && jars.contains(jar)) ||
    161                                     (no_TLD_pattern!=null && no_TLD_pattern.matcher(jar).matches())))
    162                                 continue;
    163                             jars.add(jar);
    164
    165                             Log.debug("TLD search of {}",urls[i]);
    166
    167                             File file=Resource.newResource(urls[i]).getFile();
    168                             if (file==null || !file.exists() || !file.canRead())
    169                                 continue;
    170
    171                             JarFile jarfile = null;
    172                             try
    173                             {
    174                                 jarfile = new JarFile(file);
    175                                 Enumeration e = jarfile.entries();
    176                                 while (e.hasMoreElements())
    177                                 {
    178                                     ZipEntry entry = (ZipEntry)e.nextElement();
    179                                     String name = entry.getName();
    180                                     if (name.startsWith("META-INF/") && name.toLowerCase().endsWith(".tld"))
    181                                     {
    182                                         Resource tld=Resource.newResource("jar:"+urls[i]+"!/"+name);
    183                                         tlds.add(tld);
    184                                         Log.debug("TLD found {}",tld);
    185                                     }
    186                                 }
    187                             }
    188                             catch (Exception e)
    189                             {
    190                                 Log.warn("Failed to read file: " + file, e);
    191                             }
    192                             finally
    193                             {
    194                                 if (jarfile != null)
    195                                 {
    196                                     jarfile.close();
    197                                 }
    198                             }
    199                         }
    200                     }
    201                 }
    202             }
    203
    204             loader=loader.getParent();
    205             parent=true;
    206
    207         }
    208
    209         // Create a TLD parser
    210         XmlParser parser = new XmlParser(false);
    211         parser.redirectEntity("web-jsptaglib_1_1.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd", false));
    212         parser.redirectEntity("web-jsptaglib_1_2.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd", false));
    213         parser.redirectEntity("web-jsptaglib_2_0.xsd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd", false));
    214         parser.redirectEntity("web-jsptaglibrary_1_1.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd", false));
    215         parser.redirectEntity("web-jsptaglibrary_1_2.dtd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd", false));
    216         parser.redirectEntity("web-jsptaglibrary_2_0.xsd",Loader.getResource(TagLibConfiguration.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd", false));
    217         parser.setXpath("/taglib/listener/listener-class");
    218         // Parse all the discovered TLDs
    219         Iterator iter = tlds.iterator();
    220         while (iter.hasNext())
    221         {
    222             try
    223             {
    224                 Resource tld = (Resource)iter.next();
    225                 if (Log.isDebugEnabled()) Log.debug("TLD="+tld);
    226
    227                 XmlParser.Node root;
    228
    229                 try
    230                 {
    231                     //xerces on apple appears to sometimes close the zip file instead
    232                     //of the inputstream, so try opening the input stream, but if
    233                     //that doesn't work, fallback to opening a new url
    234                     root = parser.parse(tld.getInputStream());
    235                 }
    236                 catch (Exception e)
    237                 {
    238                     root = parser.parse(tld.getURL().toString());
    239                 }
    240
    241 		if (root==null)
    242 		{
    243 		    Log.warn("No TLD root in {}",tld);
    244 		    continue;
    245 		}
    246
    247                 for (int i=0;i<root.size();i++)
    248                 {
    249                     Object o=root.get(i);
    250                     if (o instanceof XmlParser.Node)
    251                     {
    252                         XmlParser.Node node = (XmlParser.Node)o;
    253                         if ("listener".equals(node.getTag()))
    254                         {
    255                             String className=node.getString("listener-class",false,true);
    256                             if (Log.isDebugEnabled()) Log.debug("listener="+className);
    257
    258                             try
    259                             {
    260                                 Class listenerClass=getWebAppContext().loadClass(className);
    261                                 EventListener l=(EventListener)listenerClass.newInstance();
    262                                 _context.addEventListener(l);
    263                             }
    264                             catch(Exception e)
    265                             {
    266                                 Log.warn("Could not instantiate listener "+className+": "+e);
    267                                 Log.debug(e);
    268                             }
    269                             catch(Error e)
    270                             {
    271                                 Log.warn("Could not instantiate listener "+className+": "+e);
    272                                 Log.debug(e);
    273                             }
    274                         }
    275                     }
    276                 }
    277             }
    278             catch(Exception e)
    279             {
    280                 Log.warn(e);
    281             }
    282         }
    283     }
    284
    285
    286     public void deconfigureWebApp() throws Exception
    287     {
    288     }
    289
    290
    291 }