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_impl.webapp.webxml;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.net.URL;
24  import java.util.logging.Level;
25  import java.util.logging.Logger;
26  
27  import javax.faces.FacesException;
28  import javax.faces.context.ExternalContext;
29  import javax.xml.parsers.DocumentBuilder;
30  import javax.xml.parsers.DocumentBuilderFactory;
31  
32  import org.apache.myfaces.shared.util.ClassUtils;
33  import org.apache.myfaces.shared.util.xml.MyFacesErrorHandler;
34  import org.apache.myfaces.shared.util.xml.XmlUtils;
35  import org.w3c.dom.Document;
36  import org.w3c.dom.Element;
37  import org.w3c.dom.Node;
38  import org.w3c.dom.NodeList;
39  import org.xml.sax.EntityResolver;
40  import org.xml.sax.InputSource;
41  
42  /**
43   * @author Manfred Geiler (latest modification by $Author$)
44   * @version $Revision$ $Date$
45   */
46  public class WebXmlParser
47  {
48      //private static final Log log = LogFactory.getLog(WebXmlParser.class);
49      private static final Logger log = Logger.getLogger(WebXmlParser.class.getName());
50  
51      /*
52      private static final String JAXP_SCHEMA_LANGUAGE =
53          "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
54      private static final String W3C_XML_SCHEMA =
55          "http://www.w3.org/2001/XMLSchema";
56          */
57  
58      private static final String WEB_XML_PATH = "/WEB-INF/web.xml";
59  
60      private static final String WEB_APP_2_2_J2EE_SYSTEM_ID = "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd";
61      private static final String WEB_APP_2_2_SYSTEM_ID = "http://java.sun.com/dtd/web-app_2_2.dtd";
62      private static final String WEB_APP_2_2_RESOURCE  = "javax/servlet/resources/web-app_2_2.dtd";
63  
64      private static final String WEB_APP_2_3_SYSTEM_ID = "http://java.sun.com/dtd/web-app_2_3.dtd";
65      private static final String WEB_APP_2_3_RESOURCE  = "javax/servlet/resources/web-app_2_3.dtd";
66      
67      private ExternalContext _context;
68      private org.apache.myfaces.shared_impl.webapp.webxml.WebXml _webXml;
69  
70      public WebXmlParser(ExternalContext context)
71      {
72          _context = context;
73      }
74  
75      public WebXml parse()
76      {
77          _webXml = new WebXml();
78  
79          try
80          {
81              DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
82              dbf.setIgnoringElementContentWhitespace(true);
83              dbf.setIgnoringComments(true);
84              dbf.setNamespaceAware(true);
85              dbf.setValidating(false);
86  //            dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
87  
88              DocumentBuilder db = dbf.newDocumentBuilder();
89              db.setEntityResolver(new _EntityResolver());
90              db.setErrorHandler(new MyFacesErrorHandler(log));
91  
92              InputSource is = createContextInputSource(null, WEB_XML_PATH);
93  
94              if(is==null)
95              {
96                  URL url = _context.getResource(WEB_XML_PATH);
97                  log.fine("No web-xml found at : "+(url==null?" null ":url.toString()));
98                  return _webXml;
99              }
100 
101             Document document = db.parse(is);
102 
103             Element webAppElem = document.getDocumentElement();
104             if (webAppElem == null ||
105                 !webAppElem.getNodeName().equals("web-app"))
106             {
107                 throw new FacesException("No valid web-app root element found!");
108             }
109 
110             readWebApp(webAppElem);
111             
112             return _webXml;
113         }
114         catch (Exception e)
115         {
116             log.log(Level.SEVERE, "Unable to parse web.xml", e);
117             throw new FacesException(e);
118         }
119     }
120 
121     public static long getWebXmlLastModified(ExternalContext context)
122     {
123         try
124         {
125             URL url = context.getResource(WEB_XML_PATH);
126             if (url != null)
127             {
128                 return url.openConnection().getLastModified();
129             }
130         }
131         catch (IOException e)
132         {
133             log.log(Level.SEVERE, "Could not find web.xml in path " + WEB_XML_PATH);
134         }
135         return 0L;
136     }
137 
138 
139     private InputSource createContextInputSource(String publicId, String systemId)
140     {
141         InputStream inStream = _context.getResourceAsStream(systemId);
142         if (inStream == null)
143         {
144             // there is no such entity
145             return null;
146         }
147         InputSource is = new InputSource(inStream);
148         is.setPublicId(publicId);
149         is.setSystemId(systemId);
150         //the next line was removed - encoding should be determined automatically out of the inputStream
151         //DEFAULT_ENCODING was ISO-8859-1
152         //is.setEncoding(DEFAULT_ENCODING);
153         return is;
154     }
155 
156     private InputSource createClassloaderInputSource(String publicId, String systemId)
157     {
158         InputStream inStream = ClassUtils.getResourceAsStream(systemId);
159         if (inStream == null)
160         {
161             // there is no such entity
162             return null;
163         }
164         InputSource is = new InputSource(inStream);
165         is.setPublicId(publicId);
166         is.setSystemId(systemId);
167         //the next line was removed - encoding should be determined automatically out of the inputStream
168         //encoding should be determined automatically out of the inputStream
169         //DEFAULT_ENCODING was ISO-8859-1
170         //is.setEncoding(DEFAULT_ENCODING);
171         return is;
172     }
173 
174     private class _EntityResolver implements EntityResolver
175     {
176         public InputSource resolveEntity(String publicId, String systemId) throws IOException
177         {
178             if (systemId == null)
179             {
180                 throw new UnsupportedOperationException("systemId must not be null");
181             }
182 
183             if (systemId.equals(WebXmlParser.WEB_APP_2_2_SYSTEM_ID) ||
184                 systemId.equals(WebXmlParser.WEB_APP_2_2_J2EE_SYSTEM_ID))
185             {
186                 //Load DTD from servlet.jar
187                 return createClassloaderInputSource(publicId, WebXmlParser.WEB_APP_2_2_RESOURCE);
188             }
189             else if (systemId.equals(WebXmlParser.WEB_APP_2_3_SYSTEM_ID))
190             {
191                 //Load DTD from servlet.jar
192                 return createClassloaderInputSource(publicId, WebXmlParser.WEB_APP_2_3_RESOURCE);
193             }
194             else
195             {
196                 //Load additional entities from web context
197                 return createContextInputSource(publicId, systemId);
198             }
199         }
200 
201     }
202 
203 
204     private void readWebApp(Element webAppElem)
205     {
206         NodeList nodeList = webAppElem.getChildNodes();
207         for (int i = 0, len = nodeList.getLength(); i < len; i++)
208         {
209             Node n = nodeList.item(i);
210             if (n.getNodeType() == Node.ELEMENT_NODE)
211             {
212                 if (n.getNodeName().equals("servlet"))
213                 {
214                     readServlet((Element)n);
215                 }
216                 if (n.getNodeName().equals("servlet-mapping"))
217                 {
218                     readServletMapping((Element)n);
219                 }
220                 if (n.getNodeName().equals("filter"))
221                 {
222                     readFilter((Element)n);
223                 }
224                 if (n.getNodeName().equals("filter-mapping"))
225                 {
226                     readFilterMapping((Element)n);
227                 }
228                 if (n.getNodeName().equals("error-page"))
229                 {
230                     _webXml.setErrorPagePresent(true);
231                 }
232             }
233             else
234             {
235                 if (log.isLoggable(Level.FINE))
236                 {
237                     log.fine("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
238                 }
239             }
240         }
241     }
242 
243     private void readServlet(Element servletElem)
244     {
245         String servletName = null;
246         String servletClass = null;
247         NodeList nodeList = servletElem.getChildNodes();
248         for (int i = 0, len = nodeList.getLength(); i < len; i++)
249         {
250             Node n = nodeList.item(i);
251             if (n.getNodeType() == Node.ELEMENT_NODE)
252             {
253                 if (n.getNodeName().equals("servlet-name"))
254                 {
255                     servletName = XmlUtils.getElementText((Element)n);
256                 }
257                 else if (n.getNodeName().equals("servlet-class"))
258                 {
259                     servletClass = org.apache.myfaces.shared.util.xml.XmlUtils.getElementText((Element)n).trim();
260                 }
261                 else if (n.getNodeName().equals("description") || n.getNodeName().equals("load-on-startup")
262                          || n.getNodeName().equals("init-param"))
263                 {
264                     //ignore
265                 }
266                 else
267                 {
268                     if (log.isLoggable(Level.FINE))
269                     {
270                         log.fine("Ignored element '" + n.getNodeName() + "' as child of '"
271                                  + servletElem.getNodeName() + "'.");
272                     }
273                 }
274             }
275             else
276             {
277                 if (log.isLoggable(Level.FINE))
278                 {
279                     log.fine("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
280                 }
281             }
282         }
283         _webXml.addServlet(servletName, servletClass);
284     }
285 
286 
287     private void readServletMapping(Element servletMappingElem)
288     {
289         String servletName = null;
290         String urlPattern = null;
291         NodeList nodeList = servletMappingElem.getChildNodes();
292         for (int i = 0, len = nodeList.getLength(); i < len; i++)
293         {
294             Node n = nodeList.item(i);
295             if (n.getNodeType() == Node.ELEMENT_NODE)
296             {
297                 if (n.getNodeName().equals("servlet-name"))
298                 {
299                     servletName = org.apache.myfaces.shared.util.xml.XmlUtils.getElementText((Element)n);
300                 }
301                 else if (n.getNodeName().equals("url-pattern"))
302                 {
303                     urlPattern = org.apache.myfaces.shared.util.xml.XmlUtils.getElementText((Element)n).trim();
304                 }
305                 else
306                 {
307                     if (log.isLoggable(Level.FINE))
308                     {
309                         log.fine("Ignored element '" + n.getNodeName() + "' as child of '"
310                                  + servletMappingElem.getNodeName() + "'.");
311                     }
312                 }
313             }
314             else
315             {
316                 if (log.isLoggable(Level.FINE))
317                 {
318                     log.fine("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
319                 }
320             }
321         }
322         urlPattern = urlPattern.trim();
323         _webXml.addServletMapping(servletName, urlPattern);
324     }
325 
326     private void readFilter(Element filterElem)
327     {
328         String filterName = null;
329         String filterClass = null;
330         NodeList nodeList = filterElem.getChildNodes();
331         for (int i = 0, len = nodeList.getLength(); i < len; i++)
332         {
333             Node n = nodeList.item(i);
334             if (n.getNodeType() == Node.ELEMENT_NODE)
335             {
336                 if (n.getNodeName().equals("filter-name"))
337                 {
338                     filterName = XmlUtils.getElementText((Element)n).trim();
339                 }
340                 else if (n.getNodeName().equals("filter-class"))
341                 {
342                     filterClass = org.apache.myfaces.shared.util.xml.XmlUtils.getElementText((Element)n).trim();
343                 }
344                 else if (n.getNodeName().equals("description") || n.getNodeName().equals("init-param"))
345                 {
346                     //ignore
347                 }
348                 else
349                 {
350                     if (log.isLoggable(Level.FINE))
351                     {
352                         log.fine("Ignored element '" + n.getNodeName() + "' as child of '"
353                                  + filterElem.getNodeName() + "'.");
354                     }
355                 }
356             }
357             else
358             {
359                 if (log.isLoggable(Level.FINE))
360                 {
361                     log.fine("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
362                 }
363             }
364         }
365         _webXml.addFilter(filterName, filterClass);
366     }
367 
368 
369     private void readFilterMapping(Element filterMappingElem)
370     {
371         String filterName = null;
372         String urlPattern = null;
373         NodeList nodeList = filterMappingElem.getChildNodes();
374         for (int i = 0, len = nodeList.getLength(); i < len; i++)
375         {
376             Node n = nodeList.item(i);
377             if (n.getNodeType() == Node.ELEMENT_NODE)
378             {
379                 if (n.getNodeName().equals("filter-name"))
380                 {
381                     filterName = org.apache.myfaces.shared.util.xml.XmlUtils.getElementText((Element)n).trim();
382                 }
383                 else if (n.getNodeName().equals("url-pattern"))
384                 {
385                     urlPattern = org.apache.myfaces.shared.util.xml.XmlUtils.getElementText((Element)n).trim();
386                 }
387                 else if (n.getNodeName().equals("servlet-name"))
388                 {
389                     // we are not interested in servlet-name based mapping - for now
390                 }
391                 else
392                 {
393                     if (log.isLoggable(Level.FINE))
394                     {
395                         log.fine("Ignored element '" + n.getNodeName() + "' as child of '"
396                                  + filterMappingElem.getNodeName() + "'.");
397                     }
398                 }
399             }
400             else
401             {
402                 if (log.isLoggable(Level.FINE))
403                 {
404                     log.fine("Ignored node '" + n.getNodeName() + "' of type " + n.getNodeType());
405                 }
406             }
407         }
408         _webXml.addFilterMapping(filterName, urlPattern);
409     }
410 }