/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.commons.resourcehandler.webapp.config.impl;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.myfaces.commons.resourcehandler.webapp.config.WebRegistration;
import org.apache.myfaces.commons.resourcehandler.webapp.config.element.impl.FilterRegistrationImpl;
import org.apache.myfaces.commons.resourcehandler.webapp.config.element.impl.ServletRegistrationImpl;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* XML-parser for /WEB-INF/web.xml
*
* @author Leonardo Uribe
*/
public class WebXmlConfigParser
{
private static final String WEB_XML_PATH = "/WEB-INF/web.xml";
public static WebRegistration getWebRegistrationFromParsedWebXml(FacesContext facesContext)
{
try
{
URL url = facesContext.getExternalContext().getResource(WEB_XML_PATH);
if (url != null)
{
WebRegistration mrc = parseFile(facesContext, url);
return mrc;
}
else
{
return null;
}
}
catch (IOException e) {
throw new FacesException("Cannot parse /WEB-INF/web.xml file ");
}
}
private static WebRegistration parseFile(FacesContext facesContext, URL configFileUrl) throws IOException
{
InputStream is = null;
URLConnection conn = null;
try
{
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
boolean schemaValidating = false;
// parse file
WebConfigHandler handler = new WebConfigHandler(configFileUrl);
SAXParser parser = createSAXParser(handler, externalContext, schemaValidating);
conn = configFileUrl.openConnection();
conn.setUseCaches(false);
is = conn.getInputStream();
parser.parse(is, handler);
return handler.getWebConfigProvider();
}
catch (SAXException e)
{
IOException ioe = new IOException("Error parsing [" + configFileUrl + "]: ");
ioe.initCause(e);
throw ioe;
}
catch (ParserConfigurationException e)
{
IOException ioe = new IOException("Error parsing [" + configFileUrl + "]: ");
ioe.initCause(e);
throw ioe;
}
finally
{
if (is != null)
is.close();
}
}
private static final SAXParser createSAXParser(WebConfigHandler handler, ExternalContext externalContext, boolean schemaValidating) throws SAXException,
ParserConfigurationException
{
SAXParserFactory factory = SAXParserFactory.newInstance();
//Just parse it and do not validate, because it is not necessary.
factory.setNamespaceAware(true);
factory.setFeature("http://xml.org/sax/features/validation", false);
factory.setValidating(false);
SAXParser parser = factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
reader.setErrorHandler(handler);
reader.setEntityResolver(handler);
return parser;
}
private static class WebConfigHandler extends DefaultHandler
{
private final URL source;
private final StringBuffer buffer;
private Locator locator;
private WebRegistrationImpl config;
private String servletName;
private String servletClassName;
private List<String> urlPatterns;
private String filterName;
private String filterClassName;
private List<String> servletNameMappings;
public WebConfigHandler(URL source)
{
this.source = source;
this.buffer = new StringBuffer(64);
this.config = null;
}
public WebRegistration getWebConfigProvider()
{
return this.config;
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
this.buffer.setLength(0);
if ("web-app".equals(qName))
{
this.config = new WebRegistrationImpl();
this.urlPatterns = new ArrayList<String>();
this.servletNameMappings = new ArrayList<String>();
}
else if ("servlet".equals(qName))
{
this.servletName = null;
this.servletClassName = null;
}
else if ("servlet-mapping".equals(qName))
{
this.servletName = null;
this.urlPatterns.clear();
}
else if ("filter".equals(qName))
{
this.filterName = null;
this.filterClassName = null;
}
else if ("filter-mapping".equals(qName))
{
this.filterName = null;
this.urlPatterns.clear();
this.servletNameMappings.clear();
}
}
public void endElement(String uri, String localName, String qName) throws SAXException
{
try
{
if (this.config == null)
{
return;
}
if ("servlet".equals(localName))
{
ServletRegistrationImpl sr = (ServletRegistrationImpl) this.config.getServletRegistration(this.servletName);
if (sr == null)
{
sr = new ServletRegistrationImpl(this.servletName, this.servletClassName);
}
else
{
sr.setClassName(this.servletClassName);
}
this.config.getServletRegistrations().put(this.servletName, sr);
}
else if ("servlet-name".equals(localName))
{
servletName = captureBuffer();
}
else if ("servlet-class".equals(localName))
{
servletClassName = captureBuffer();
}
else if ("filter".equals(localName))
{
FilterRegistrationImpl sr = (FilterRegistrationImpl) this.config.getFilterRegistration(this.filterName);
if (sr == null)
{
sr = new FilterRegistrationImpl(this.filterName, this.filterClassName);
}
else
{
sr.setClassName(this.filterClassName);
}
this.config.getFilterRegistrations().put(this.filterName, sr);
}
else if ("filter-name".equals(localName))
{
filterName = captureBuffer();
}
else if ("filter-class".equals(localName))
{
filterClassName = captureBuffer();
}
else if ("servlet-mapping".equals(localName))
{
ServletRegistrationImpl sr = (ServletRegistrationImpl) this.config.getServletRegistration(this.servletName);
if (sr == null)
{
sr = new ServletRegistrationImpl(this.servletName);
this.config.getServletRegistrations().put(this.servletName, sr);
}
for (String url: urlPatterns)
{
sr.addMapping(url);
}
}
else if ("filter-mapping".equals(localName))
{
FilterRegistrationImpl sr = (FilterRegistrationImpl) this.config.getFilterRegistration(this.filterName);
if (sr == null)
{
sr = new FilterRegistrationImpl(this.filterName);
this.config.getFilterRegistrations().put(this.filterName, sr);
}
for (String url: urlPatterns)
{
sr.addUrlNameMapping(url);
}
for (String name : servletNameMappings)
{
sr.addServletNameMapping(name);
}
urlPatterns.clear();
servletNameMappings.clear();
}
else if ("url-pattern".equals(localName))
{
urlPatterns.add(captureBuffer());
}
}
catch (Exception e)
{
SAXException saxe = new SAXException("Error Handling [" + this.source + "@"
+ this.locator.getLineNumber() + "," + this.locator.getColumnNumber() + "] <" + qName + ">");
saxe.initCause(e);
throw saxe;
}
}
public void characters(char[] ch, int start, int length) throws SAXException
{
this.buffer.append(ch, start, length);
}
private String captureBuffer() throws Exception
{
String s = this.buffer.toString().trim();
if (s.length() == 0)
{
throw new Exception("Value Cannot be Empty");
}
this.buffer.setLength(0);
return s;
}
public InputSource resolveEntity(String publicId, String systemId) throws SAXException
{
return null;
}
public void error(SAXParseException e) throws SAXException
{
SAXException saxe = new SAXException("Error Handling [" + this.source + "@" + e.getLineNumber() + ","
+ e.getColumnNumber() + "]");
saxe.initCause(e);
throw saxe;
}
public void setDocumentLocator(Locator locator)
{
this.locator = locator;
}
public void fatalError(SAXParseException e) throws SAXException
{
throw e;
}
public void warning(SAXParseException e) throws SAXException
{
throw e;
}
}
}