View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
    10   *   http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing,
    13   * software distributed under the License is distributed on an
    14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   * KIND, either express or implied.  See the License for the
    16   * specific language governing permissions and limitations
    17   * under the License.
    18   */
    19  package org.apache.myfaces.shared_orchestra.webapp.webxml;
    20
    21  import org.apache.myfaces.shared_orchestra.util.xml.MyFacesErrorHandler;
    22  import org.apache.myfaces.shared_orchestra.util.xml.XmlUtils;
    23  import org.apache.myfaces.shared_orchestra.webapp.webxml.WebXml;
    24  import org.apache.commons.logging.Log;
    25  import org.apache.commons.logging.LogFactory;
    26  import org.w3c.dom.Document;
    27  import org.w3c.dom.Element;
    28  import org.w3c.dom.Node;
    29  import org.w3c.dom.NodeList;
    30  import org.xml.sax.EntityResolver;
    31  import org.xml.sax.InputSource;
    32
    33  import javax.faces.FacesException;
    34  import javax.faces.context.ExternalContext;
    35  import javax.xml.parsers.DocumentBuilder;
    36  import javax.xml.parsers.DocumentBuilderFactory;
    37  import java.io.IOException;
    38  import java.io.InputStream;
    39  import java.net.URL;
    40
    41  /**
    42   * @author Manfred Geiler (latest modification by $Author: skitching $)
    43   * @version $Revision: 673826 $ $Date: 2008-07-03 16:43:52 -0500 (Thu, 03 Jul 2008) $
    44   */
    45  public class WebXmlParser
    46  {
    47      private static final Log log = LogFactory.getLog(WebXmlParser.class);
    48
    49      /*
    50      private static final String JAXP_SCHEMA_LANGUAGE =
    51          "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    52      private static final String W3C_XML_SCHEMA =
    53          "http://www.w3.org/2001/XMLSchema";
    54          */
    55
    56      private static final String WEB_XML_PATH = "/WEB-INF/web.xml";
    57
    58      private static final String WEB_APP_2_2_J2EE_SYSTEM_ID = "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd";
    59      private static final String WEB_APP_2_2_SYSTEM_ID = "http://java.sun.com/dtd/web-app_2_2.dtd";
    60      private static final String WEB_APP_2_2_RESOURCE  = "javax/servlet/resources/web-app_2_2.dtd";
    61
    62      private static final String WEB_APP_2_3_SYSTEM_ID = "http://java.sun.com/dtd/web-app_2_3.dtd";
    63      private static final String WEB_APP_2_3_RESOURCE  = "javax/servlet/resources/web-app_2_3.dtd";
    64
    65      private ExternalContext _context;
    66      private org.apache.myfaces.shared_orchestra.webapp.webxml.WebXml _webXml;
    67
    68      public WebXmlParser(ExternalContext context)
    69      {
    70          _context = context;
    71      }
    72
    73      public WebXml parse()
    74      {
    75          _webXml = new WebXml();
    76
    77          try
    78          {
    79              DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    80              dbf.setIgnoringElementContentWhitespace(true);
    81              dbf.setIgnoringComments(true);
    82              dbf.setNamespaceAware(true);
    83              dbf.setValidating(false);
    84  //            dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
    85
    86              DocumentBuilder db = dbf.newDocumentBuilder();
    87              db.setEntityResolver(new _EntityResolver());
    88              db.setErrorHandler(new MyFacesErrorHandler(log));
    89
    90              InputSource is = createContextInputSource(null, WEB_XML_PATH);
    91
    92              if(is==null)
    93              {
    94                  URL url = _context.getResource(WEB_XML_PATH);
    95                  log.debug("No web-xml found at : "+(url==null?" null ":url.toString()));
    96                  return _webXml;
    97              }
    98
    99              Document document = db.parse(is);
    100
    101             Element webAppElem = document.getDocumentElement();
    102             if (webAppElem == null ||
    103                 !webAppElem.getNodeName().equals("web-app"))
    104             {
    105                 throw new FacesException("No valid web-app root element found!");
    106             }
    107
    108             readWebApp(webAppElem);
    109
    110             return _webXml;
    111         }
    112         catch (Exception e)
    113         {
    114             log.fatal("Unable to parse web.xml", e);
    115             throw new FacesException(e);
    116         }
    117     }
    118
    119     public static long getWebXmlLastModified(ExternalContext context) {
    120         try {
    121             URL url = context.getResource(WEB_XML_PATH);
    122             if (url != null)
    123                 return url.openConnection().getLastModified();
    124         } catch (IOException e) {
    125             log.error("Could not find web.xml in path " + WEB_XML_PATH);
    126         }
    127         return 0L;
    128     }
    129
    130
    131     private InputSource createContextInputSource(String publicId, String systemId)
    132     {
    133         InputStream inStream = _context.getResourceAsStream(systemId);
    134         if (inStream == null)
    135         {
    136             // there is no such entity
    137             return null;
    138         }
    139         InputSource is = new InputSource(inStream);
    140         is.setPublicId(publicId);
    141         is.setSystemId(systemId);
    142         //the next line was removed - encoding should be determined automatically out of the inputStream
    143         //DEFAULT_ENCODING was ISO-8859-1
    144         //is.setEncoding(DEFAULT_ENCODING);
    145         return is;
    146     }
    147
    148     private InputSource createClassloaderInputSource(String publicId, String systemId)
    149     {
    150         InputStream inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(systemId);
    151         if (inStream == null)
    152         {
    153             // there is no such entity
    154             return null;
    155         }
    156         InputSource is = new InputSource(inStream);
    157         is.setPublicId(publicId);
    158         is.setSystemId(systemId);
    159         //the next line was removed - encoding should be determined automatically out of the inputStream
    160         //encoding should be determined automatically out of the inputStream
    161         //DEFAULT_ENCODING was ISO-8859-1
    162         //is.setEncoding(DEFAULT_ENCODING);
    163         return is;
    164     }
    165
    166     private class _EntityResolver implements EntityResolver
    167     {
    168         public InputSource resolveEntity(String publicId, String systemId) throws IOException
    169         {
    170             if (systemId == null)
    171             {
    172                 throw new UnsupportedOperationException("systemId must not be null");
    173             }
    174
    175             if (systemId.equals(WebXmlParser.WEB_APP_2_2_SYSTEM_ID) ||
    176                 systemId.equals(WebXmlParser.WEB_APP_2_2_J2EE_SYSTEM_ID))
    177             {
    178                 //Load DTD from servlet.jar
    179                 return createClassloaderInputSource(publicId, WebXmlParser.WEB_APP_2_2_RESOURCE);
    180             }
    181             else if (systemId.equals(WebXmlParser.WEB_APP_2_3_SYSTEM_ID))
    182             {
    183                 //Load DTD from servlet.jar
    184                 return createClassloaderInputSource(publicId, WebXmlParser.WEB_APP_2_3_RESOURCE);
    185             }
    186             else
    187             {
    188                 //Load additional entities from web context
    189                 return createContextInputSource(publicId, systemId);
    190             }
    191         }
    192
    193     }
    194
    195
    196     private void readWebApp(Element webAppElem)
    197     {
    198         NodeList nodeList = webAppElem.getChildNodes();
    199         for (int i = 0, len = nodeList.getLength(); i < len; i++)
    200         {
    201             Node n = nodeList.item(i);
    202             if (n.getNodeType() == Node.ELEMENT_NODE)
    203             {
    204                 if (n.getNodeName().equals("servlet"))
    205                 {
    206                     readServlet((Element)n);
    207                 }
    208                 if (n.getNodeName().equals("servlet-mapping"))
    209                 {
    210                     readServletMapping((Element)n);
    211                 }
    212                 if (n.getNodeName().equals("filter"))
    213                 {
    214                     readFilter((Element)n);
    215                 }
    216                 if (n.getNodeName().equals("filter-mapping"))
    217                 {
    218                     readFilterMapping((Element)n);
    219                 }
    220             }
    221             else
    222             {
    223                 if (log.isDebugEnabled()) log.debug("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
    224             }
    225         }
    226     }
    227
    228     private void readServlet(Element servletElem)
    229     {
    230         String servletName = null;
    231         String servletClass = null;
    232         NodeList nodeList = servletElem.getChildNodes();
    233         for (int i = 0, len = nodeList.getLength(); i < len; i++)
    234         {
    235             Node n = nodeList.item(i);
    236             if (n.getNodeType() == Node.ELEMENT_NODE)
    237             {
    238                 if (n.getNodeName().equals("servlet-name"))
    239                 {
    240                     servletName = XmlUtils.getElementText((Element)n);
    241                 }
    242                 else if (n.getNodeName().equals("servlet-class"))
    243                 {
    244                     servletClass = org.apache.myfaces.shared_orchestra.util.xml.XmlUtils.getElementText((Element)n).trim();
    245                 }
    246                 else if (n.getNodeName().equals("description") || n.getNodeName().equals("load-on-startup") || n.getNodeName().equals("init-param"))
    247                 {
    248                     //ignore
    249                 }
    250                 else
    251                 {
    252                     if (log.isDebugEnabled()) log.debug("Ignored element '" + n.getNodeName() + "' as child of '" + servletElem.getNodeName() + "'.");
    253                 }
    254             }
    255             else
    256             {
    257                 if (log.isDebugEnabled()) log.debug("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
    258             }
    259         }
    260         _webXml.addServlet(servletName, servletClass);
    261     }
    262
    263
    264     private void readServletMapping(Element servletMappingElem)
    265     {
    266         String servletName = null;
    267         String urlPattern = null;
    268         NodeList nodeList = servletMappingElem.getChildNodes();
    269         for (int i = 0, len = nodeList.getLength(); i < len; i++)
    270         {
    271             Node n = nodeList.item(i);
    272             if (n.getNodeType() == Node.ELEMENT_NODE)
    273             {
    274                 if (n.getNodeName().equals("servlet-name"))
    275                 {
    276                     servletName = org.apache.myfaces.shared_orchestra.util.xml.XmlUtils.getElementText((Element)n);
    277                 }
    278                 else if (n.getNodeName().equals("url-pattern"))
    279                 {
    280                     urlPattern = org.apache.myfaces.shared_orchestra.util.xml.XmlUtils.getElementText((Element)n).trim();
    281                 }
    282                 else
    283                 {
    284                     if (log.isWarnEnabled()) log.warn("Ignored element '" + n.getNodeName() + "' as child of '" + servletMappingElem.getNodeName() + "'.");
    285                 }
    286             }
    287             else
    288             {
    289                 if (log.isDebugEnabled()) log.debug("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
    290             }
    291         }
    292         urlPattern = urlPattern.trim();
    293         _webXml.addServletMapping(servletName, urlPattern);
    294     }
    295
    296     private void readFilter(Element filterElem)
    297     {
    298         String filterName = null;
    299         String filterClass = null;
    300         NodeList nodeList = filterElem.getChildNodes();
    301         for (int i = 0, len = nodeList.getLength(); i < len; i++)
    302         {
    303             Node n = nodeList.item(i);
    304             if (n.getNodeType() == Node.ELEMENT_NODE)
    305             {
    306                 if (n.getNodeName().equals("filter-name"))
    307                 {
    308                     filterName = XmlUtils.getElementText((Element)n).trim();
    309                 }
    310                 else if (n.getNodeName().equals("filter-class"))
    311                 {
    312                     filterClass = org.apache.myfaces.shared_orchestra.util.xml.XmlUtils.getElementText((Element)n).trim();
    313                 }
    314                 else if (n.getNodeName().equals("description") || n.getNodeName().equals("init-param"))
    315                 {
    316                     //ignore
    317                 }
    318                 else
    319                 {
    320                     if (log.isDebugEnabled()) log.debug("Ignored element '" + n.getNodeName() + "' as child of '" + filterElem.getNodeName() + "'.");
    321                 }
    322             }
    323             else
    324             {
    325                 if (log.isDebugEnabled()) log.debug("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
    326             }
    327         }
    328         _webXml.addFilter(filterName, filterClass);
    329     }
    330
    331
    332     private void readFilterMapping(Element filterMappingElem)
    333     {
    334         String filterName = null;
    335         String urlPattern = null;
    336         NodeList nodeList = filterMappingElem.getChildNodes();
    337         for (int i = 0, len = nodeList.getLength(); i < len; i++)
    338         {
    339             Node n = nodeList.item(i);
    340             if (n.getNodeType() == Node.ELEMENT_NODE)
    341             {
    342                 if (n.getNodeName().equals("filter-name"))
    343                 {
    344                     filterName = org.apache.myfaces.shared_orchestra.util.xml.XmlUtils.getElementText((Element)n).trim();
    345                 }
    346                 else if (n.getNodeName().equals("url-pattern"))
    347                 {
    348                     urlPattern = org.apache.myfaces.shared_orchestra.util.xml.XmlUtils.getElementText((Element)n).trim();
    349                 }
    350                 else if (n.getNodeName().equals("servlet-name"))
    351                 {
    352                     // we are not interested in servlet-name based mapping - for now
    353                 }
    354                 else if (n.getNodeName().equals("dispatcher"))
    355                 {
    356                     // we are not interested in dispatcher instructions
    357                 }
    358                 else
    359                 {
    360                     if (log.isWarnEnabled()) log.warn("Ignored element '" + n.getNodeName() + "' as child of '" + filterMappingElem.getNodeName() + "'.");
    361                 }
    362             }
    363             else
    364             {
    365                 if (log.isDebugEnabled()) log.debug("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
    366             }
    367         }
    368         _webXml.addFilterMapping(filterName, urlPattern);
    369     }
    370 }