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