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 }