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   * &lt;bile&gt;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   * &lt;/bile&gt;
    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 }