All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.webapp.TagLibConfiguration Maven / Gradle / Ivy

There is a newer version: 11.0.0.beta1
Show newest version
// ========================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at 
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses. 
// ========================================================================

package org.eclipse.jetty.webapp;

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.Servlet;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlParser;

/* ------------------------------------------------------------ */
/** TagLibConfiguration.
 * 
 * The class searches for TLD descriptors found in web.xml, in WEB-INF/*.tld files of the web app
 * or *.tld files within jars found in WEB-INF/lib of the webapp.   Any listeners defined in these
 * tld's are added to the context.
 * 
 * <bile>This is total rubbish special case for JSPs! If there was a general use-case for web app
 * frameworks to register listeners directly, then a generic mechanism could have been added to the servlet
 * spec.  Instead some special purpose JSP support is required that breaks all sorts of encapsulation rules as
 * the servlet container must go searching for and then parsing the descriptors for one particular framework.
 * It only appears to be used by JSF, which is being developed by the same developer who implemented this
 * feature in the first place!
 * </bile>
 * 
 * 
 * Note- this has been superceded by the new TldScanner in jasper which uses ServletContainerInitializer to
 * find all the listeners in tag libs and register them.
 */
public class TagLibConfiguration extends AbstractConfiguration
{
    private static final Logger LOG = Log.getLogger(TagLibConfiguration.class);

    public static final String TLD_RESOURCES = "org.eclipse.jetty.tlds";
    
  
    /**
     * TagLibListener
     *
     * A listener that does the job of finding .tld files that contain
     * (other) listeners that need to be called by the servlet container.
     * 
     * This implementation is necessitated by the fact that it is only
     * after all the Configuration classes have run that we will
     * parse web.xml/fragments etc and thus find tlds mentioned therein.
     * 
     * Note: TagLibConfiguration is not used in jetty-8 as jasper (JSP engine)
     * uses the new TldScanner class - a ServletContainerInitializer from
     * Servlet Spec 3 - to find all listeners in taglibs and register them
     * with the servlet container.
     */
    public  class TagLibListener implements ServletContextListener {
        private List _tldListeners;
        private WebAppContext _context;       
        
        public TagLibListener (WebAppContext context) {
            _context = context;
        }

        public void contextDestroyed(ServletContextEvent sce)
        {
            if (_tldListeners == null)
                return;
            
            for (int i=_tldListeners.size()-1; i>=0; i--) {
                EventListener l = _tldListeners.get(i);
                if (l instanceof ServletContextListener) {
                    ((ServletContextListener)l).contextDestroyed(sce);
                }
            }
        }

        public void contextInitialized(ServletContextEvent sce)
        {
            try 
            {
                //For jasper 2.1: 
                //Get the system classpath tlds and tell jasper about them, if jasper is on the classpath
                try
                {
                    Class clazz = getClass().getClassLoader().loadClass("org.apache.jasper.compiler.TldLocationsCache");
                    Collection tld_resources = (Collection)_context.getAttribute(TLD_RESOURCES);
                   
                    Map> tldMap = new HashMap>();
                    
                    if (tld_resources != null)
                    {
                        //get the jar file names of the files
                        for (Resource r:tld_resources)
                        {
                            Resource jarResource = extractJarResource(r);
                            //jasper is happy with an empty list of tlds
                            if (!tldMap.containsKey(jarResource.getURI()))
                                tldMap.put(jarResource.getURI(), null);

                        }
                        //set the magic context attribute that tells jasper about the system tlds
                        sce.getServletContext().setAttribute("com.sun.appserv.tld.map", tldMap);
                    }
                }
                catch (ClassNotFoundException e)
                {
                    LOG.ignore(e);
                }
               
                //find the tld files and parse them to get out their
                //listeners
                Set tlds = findTldResources();
                List descriptors = parseTlds(tlds);
                processTlds(descriptors);
                
                if (_tldListeners == null)
                    return;
                
                //call the listeners that are ServletContextListeners, put the
                //rest into the context's list of listeners to call at the appropriate
                //moment
                for (EventListener l:_tldListeners) {
                    if (l instanceof ServletContextListener) {
                        ((ServletContextListener)l).contextInitialized(sce);
                    } else {
                        _context.addEventListener(l);
                    }
                }
                
            } 
            catch (Exception e) {
                LOG.warn(e);
            }
        }


        
        
        private Resource extractJarResource (Resource r)
        {
            if (r == null)
                return null;
            
            try
            {
                String url = r.getURI().toURL().toString();
                int idx = url.lastIndexOf("!/");
                if (idx >= 0)
                    url = url.substring(0, idx);
                if (url.startsWith("jar:"))
                    url = url.substring(4);
                return Resource.newResource(url);
            }
            catch (IOException e)
            {
                LOG.warn(e);
                return null;
            }
        }
    
        /**
         * Find all the locations that can harbour tld files that may contain
         * a listener which the web container is supposed to instantiate and
         * call.
         * 
         * @return
         * @throws IOException
         */
        private Set findTldResources () throws IOException {
            
            Set tlds = new HashSet();
            
            // Find tld's from web.xml
            // When web.xml was processed, it should have created aliases for all TLDs.  So search resources aliases
            // for aliases ending in tld
            if (_context.getResourceAliases()!=null && 
                    _context.getBaseResource()!=null && 
                    _context.getBaseResource().exists())
            {
                Iterator iter=_context.getResourceAliases().values().iterator();
                while(iter.hasNext())
                {
                    String location = iter.next();
                    if (location!=null && location.toLowerCase().endsWith(".tld"))
                    {
                        if (!location.startsWith("/"))
                            location="/WEB-INF/"+location;
                        Resource l=_context.getBaseResource().addPath(location);
                        tlds.add(l);
                    }
                }
            }
            
            // Look for any tlds in WEB-INF directly.
            Resource web_inf = _context.getWebInf();
            if (web_inf!=null)
            {
                String[] contents = web_inf.list();
                for (int i=0;contents!=null && i tld_resources=(Collection)_context.getAttribute(TLD_RESOURCES);
            if (tld_resources!=null)
                tlds.addAll(tld_resources);
            
            return tlds;
        }
        
        
        /**
         * Parse xml into in-memory tree
         * @param tlds
         * @return
         */
        private List parseTlds (Set tlds) {         
            List descriptors = new ArrayList();
            
            Resource tld = null;
            Iterator iter = tlds.iterator();
            while (iter.hasNext())
            {
                try
                {
                    tld = iter.next();
                    if (LOG.isDebugEnabled()) LOG.debug("TLD="+tld);
                   
                    TldDescriptor d = new TldDescriptor(tld);
                    d.parse();
                    descriptors.add(d);
                }
                catch(Exception e)
                {
                    LOG.warn("Unable to parse TLD: " + tld,e);
                }
            }
            return descriptors;
        }
        
        
        /**
         * Create listeners from the parsed tld trees
         * @param descriptors
         * @throws Exception
         */
        private void processTlds (List descriptors) throws Exception {

            TldProcessor processor = new TldProcessor();
            for (TldDescriptor d:descriptors)
                processor.process(_context, d); 
            
            _tldListeners = new ArrayList(processor.getListeners());
        }
    }
    
    
    
    
    /**
     * TldDescriptor
     *
     *
     */
    public static class TldDescriptor extends Descriptor
    {
        protected static XmlParser __parserSingleton;

        public TldDescriptor(Resource xml)
        {
            super(xml);
        }

        @Override
        public void ensureParser() throws ClassNotFoundException
        {
           if (__parserSingleton == null)
               __parserSingleton = newParser();
            _parser = __parserSingleton;
        }

        @Override
        public XmlParser newParser() throws ClassNotFoundException
        {
            // Create a TLD parser
            XmlParser parser = new XmlParser(false);
            
            URL taglib11=null;
            URL taglib12=null;
            URL taglib20=null;
            URL taglib21=null;

            try
            {
                Class jsp_page = Loader.loadClass(WebXmlConfiguration.class,"javax.servlet.jsp.JspPage");
                taglib11=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd");
                taglib12=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd");
                taglib20=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd");
                taglib21=jsp_page.getResource("javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd");
            }
            catch(Exception e)
            {
                LOG.ignore(e);
            }
            finally
            {
                if(taglib11==null)
                    taglib11=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd",true);
                if(taglib12==null)
                    taglib12=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd",true);
                if(taglib20==null)
                    taglib20=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd",true);
                if(taglib21==null)
                    taglib21=Loader.getResource(Servlet.class,"javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd",true);
            }
            

            if(taglib11!=null)
            {
                redirect(parser, "web-jsptaglib_1_1.dtd",taglib11);  
                redirect(parser, "web-jsptaglibrary_1_1.dtd",taglib11);
            }
            if(taglib12!=null)
            {
                redirect(parser, "web-jsptaglib_1_2.dtd",taglib12);
                redirect(parser, "web-jsptaglibrary_1_2.dtd",taglib12);
            }
            if(taglib20!=null)
            {
                redirect(parser, "web-jsptaglib_2_0.xsd",taglib20);
                redirect(parser, "web-jsptaglibrary_2_0.xsd",taglib20);
            }
            if(taglib21!=null)
            {
                redirect(parser, "web-jsptaglib_2_1.xsd",taglib21);
                redirect(parser, "web-jsptaglibrary_2_1.xsd",taglib21);
            }
            
            parser.setXpath("/taglib/listener/listener-class");
            return parser;
        }
        
        public void parse ()
        throws Exception
        {
            ensureParser();
            try
            {
                //xerces on apple appears to sometimes close the zip file instead
                //of the inputstream, so try opening the input stream, but if
                //that doesn't work, fallback to opening a new url
                _root = _parser.parse(_xml.getInputStream());
            }
            catch (Exception e)
            {
                _root = _parser.parse(_xml.getURL().toString());
            }

            if (_root==null)
            {
                LOG.warn("No TLD root in {}",_xml);
            }
        }
    }
    
    
    /**
     * TldProcessor
     *
     * Process TldDescriptors representing tag libs to find listeners.
     */
    public class TldProcessor extends IterativeDescriptorProcessor
    {
        public static final String TAGLIB_PROCESSOR = "org.eclipse.jetty.tagLibProcessor";
        XmlParser _parser;
        List _roots = new ArrayList();
        List _listeners;
        
        
        public TldProcessor ()
        throws Exception
        {  
            _listeners = new ArrayList();
            registerVisitor("listener", this.getClass().getDeclaredMethod("visitListener", __signature));
        }
      

        public void visitListener (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
        {     
            String className=node.getString("listener-class",false,true);
            if (LOG.isDebugEnabled()) 
                LOG.debug("listener="+className);

            try
            {
                Class listenerClass = context.loadClass(className);
                EventListener l = (EventListener)listenerClass.newInstance();
                _listeners.add(l);
            }
            catch(Exception e)
            {
                LOG.warn("Could not instantiate listener "+className+": "+e);
                LOG.debug(e);
            }
            catch(Error e)
            {
                LOG.warn("Could not instantiate listener "+className+": "+e);
                LOG.debug(e);
            }

        }

        @Override
        public void end(WebAppContext context, Descriptor descriptor)
        {
        }

        @Override
        public void start(WebAppContext context, Descriptor descriptor)
        {  
        }
        
        public List getListeners() {
            return _listeners;
        }
    }


    @Override
    public void preConfigure(WebAppContext context) throws Exception
    {
        try
        {
            Class jsp_page = Loader.loadClass(WebXmlConfiguration.class,"javax.servlet.jsp.JspPage");
        }
        catch (Exception e)
        {
            //no jsp available, don't parse TLDs
            return;
        }

        TagLibListener tagLibListener = new TagLibListener(context);
        context.addEventListener(tagLibListener);
    }
    

    @Override
    public void configure (WebAppContext context) throws Exception
    {         
    }

    @Override
    public void postConfigure(WebAppContext context) throws Exception
    {     
    }


    @Override
    public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
    {
    }


    @Override
    public void deconfigure(WebAppContext context) throws Exception
    {
    } 
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy