/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.seam.faces.projectstage;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Simple SAX parser for reading "context-param" entries from web.xml
*
* @author Christian Kaltepoth <christian@kaltepoth.de>
*
*/
public class WebXmlContextParameterParser extends DefaultHandler {
/**
* Used to maintain a list of elements up to the root of the XML tree
*/
private final Stack<String> stack = new Stack<String>();
/**
* All context parameters parsed from the file
*/
private final Map<String, String> entries = new HashMap<String, String>();
/**
* The current name and value
*/
private String currentName;
private String currentValue;
/**
* Parses the supplied web.xml {@link InputStream}.
*
* @param stream The stream to parse
* @throws IOException for any errors during the parsing process
*/
public final void parse(InputStream stream) throws IOException {
// all XML exceptions are wrapped by IOExceptions
try {
// setup a namespace aware SAXParserFactory
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setNamespaceAware(true);
// parse the input stream
SAXParser parser = saxParserFactory.newSAXParser();
parser.parse(stream, this);
} catch (ParserConfigurationException e) {
throw new IOException(e);
} catch (SAXException e) {
throw new IOException(e);
}
}
/**
* Returns the value of the supplied context parameter parsed from the web.xml file. Returns <code>null</code> if the parser
* found no value for this parameter.
*
* @param name The name of the context parameter
* @return the value or <code>null</code>
*/
public String getContextParameter(String name) {
return entries.get(name);
}
/*
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String,
* org.xml.sax.Attributes)
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// update element stack
stack.add(localName);
// <context-param>
if (elements("web-app", "context-param")) {
currentName = null;
currentValue = null;
}
}
/*
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// <param-name>
if (elements("web-app", "context-param", "param-name")) {
currentName = String.valueOf(ch, start, length).trim();
}
// <param-value>
if (elements("web-app", "context-param", "param-value")) {
currentValue = String.valueOf(ch, start, length).trim();
}
}
/*
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// <context-param>
if (elements("web-app", "context-param")) {
if (currentName != null && currentValue != null) {
entries.put(currentName, currentValue);
}
}
// remove the element from the stack
String removedName = stack.pop();
// check if the removed name is the expected one
if (!removedName.equals(localName)) {
throw new IllegalStateException("Found '" + removedName + "' but expected '" + localName + "' on the stack!");
}
}
/**
* Checks whether the element stack currently contains exactly the elements supplied by the caller. This method can be used
* to find the current position in the document. The first argument is always the root element of the document, the second
* is a child of the root element, and so on. The method uses the local names of the elements only. Namespaces are ignored.
*
* @param name The names of the parent elements
* @return <code>true</code> if the parent element stack contains exactly these elements
*/
protected boolean elements(String... name) {
if (name == null || name.length != stack.size()) {
return false;
}
for (int i = 0; i < name.length; i++) {
if (!name[i].equals(stack.get(i))) {
return false;
}
}
return true;
}
}