/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.validation.xml;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* ReaderUtils purpose.
*
* <p>
* This class is intended to be used as a library of XML relevant operation for
* the XMLConfigReader class.
* </p>
*
* <p></p>
*
* @author dzwiers, Refractions Research, Inc.
* @source $URL$
* @version $Id$
*
* @see XMLConfigReader
*/
class ReaderUtils {
/** Used internally to create log information to detect errors. */
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(
"org.vfny.geoserver.global");
/**
* ReaderUtils constructor.
*
* <p>
* Static class, this should never be called.
* </p>
*/
private ReaderUtils() {
}
/**
* loadConfig purpose.
*
* <p>
* Parses the specified file into a DOM tree.
* </p>
*
* @param configFile The file to parse int a DOM tree.
*
* @return the resulting DOM tree
*
* @throws ParserConfigurationException DOCUMENT ME!
* @throws ParserConfigurationException
* @throws SAXException DOCUMENT ME!
*/
public static Element loadConfig(Reader configFile)
throws IOException, ParserConfigurationException, SAXException {
LOGGER.finest("loading configuration file " + configFile);
InputSource in = new InputSource(configFile);
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setNamespaceAware(true);
// TODO turn on validation
dfactory.setValidating(false);
dfactory.setIgnoringComments(true);
dfactory.setCoalescing(true);
dfactory.setIgnoringElementContentWhitespace(true);
Document serviceDoc = dfactory.newDocumentBuilder().parse(in);
Element configElem = serviceDoc.getDocumentElement();
return configElem;
}
/**
* initFile purpose.
*
* <p>
* Checks to ensure the file is valid. Returns the file passed in to allow
* this to wrap file creations.
* </p>
*
* @param f A file Handle to test.
* @param isDir true when the File passed in is expected to be a directory,
* false when the handle is expected to be a file.
*
* @return the File handle passed in
*
* @throws IOException When the file does not exist or is not the type
* specified.
*/
public static File initFile(File f, boolean isDir)
throws IOException {
if (!f.exists()) {
throw new IOException(
"Path specified does not have a valid file.\n" + f + "\n\n");
}
if (isDir && !f.isDirectory()) {
throw new IOException(
"Path specified does not have a valid file.\n" + f + "\n\n");
}
if (!isDir && !f.isFile()) {
throw new IOException(
"Path specified does not have a valid file.\n" + f + "\n\n");
}
LOGGER.fine("File is valid: " + f);
return f;
}
/**
* getChildElement purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child element of
* the specified name. An exception occurs when the node is required and
* not found.
* </p>
*
* @param root The root element to look for children in.
* @param name The name of the child element to look for.
* @param mandatory true when an exception should be thrown if the child
* element does not exist.
*
* @return The child element found, null if not found.
*
* @throws SAXException When a child element is required and not found.
*/
public static Element getChildElement(Element root, String name,
boolean mandatory) throws SAXException {
Node child = root.getFirstChild();
while (child != null) {
if (child.getNodeType() == Node.ELEMENT_NODE) {
if (name.equals(child.getNodeName())) {
return (Element) child;
}
}
child = child.getNextSibling();
}
if (mandatory && (child == null)) {
throw new SAXException(root.getNodeName()
+ " does not contains a child element named " + name);
}
return null;
}
/**
* getChildElement purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child element of
* the specified name.
* </p>
*
* @param root The root element to look for children in.
* @param name The name of the child element to look for.
*
* @return The child element found, null if not found.
*
* @see getChildElement(Element,String,boolean)
*/
public static Element getChildElement(Element root, String name) {
try {
return getChildElement(root, name, false);
} catch (SAXException e) {
//will never be here.
return null;
}
}
/**
* getIntAttribute purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child integer
* attribute of the specified name. An exception occurs when the node is
* required and not found.
* </p>
*
* @param elem The root element to look for children in.
* @param attName The name of the attribute to look for.
* @param mandatory true when an exception should be thrown if the
* attribute element does not exist.
* @param defaultValue a default value to return incase the attribute was
* not found. mutually exclusive with the ConfigurationException
* thrown.
*
* @return The int value if the attribute was found, the default otherwise.
*
* @throws SAXException When a attribute element is required and not found.
*/
public static int getIntAttribute(Element elem, String attName,
boolean mandatory, int defaultValue) throws SAXException {
String attValue = getAttribute(elem, attName, mandatory);
if (!mandatory && (attValue == null)) {
return defaultValue;
}
try {
return Integer.parseInt(attValue);
} catch (Exception ex) {
if (mandatory) {
throw new SAXException(attName + " attribute of element "
+ elem.getNodeName() + " must be an integer, but it's '"
+ attValue + "'");
} else {
return defaultValue;
}
}
}
/**
* getIntAttribute purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child integer
* attribute of the specified name. An exception occurs when the node is
* required and not found.
* </p>
*
* @param elem The root element to look for children in.
* @param attName The name of the attribute to look for.
* @param mandatory true when an exception should be thrown if the
* attribute element does not exist.
*
* @return The value if the attribute was found, the null otherwise.
*
* @throws SAXException When a child attribute is required and not found.
*/
public static String getAttribute(Element elem, String attName,
boolean mandatory) throws SAXException {
Attr att = elem.getAttributeNode(attName);
String value = null;
if (att != null) {
value = att.getValue();
}
if (mandatory) {
if (att == null) {
throw new SAXException("element " + elem.getNodeName()
+ " does not contains an attribute named " + attName);
} else if ("".equals(value)) {
throw new SAXException("attribute " + attName + "in element "
+ elem.getNodeName() + " is empty");
}
}
return value;
}
/**
* getBooleanAttribute purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child integer
* attribute of the specified name. An exception occurs when the node is
* required and not found.
* </p>
*
* @param elem The root element to look for children in.
* @param attName The name of the attribute to look for.
* @param mandatory true when an exception should be thrown if the
* attribute element does not exist.
*
* @return The value if the attribute was found, the false otherwise.
*
* @throws SAXException When a child attribute is required and not found.
*/
public static boolean getBooleanAttribute(Element elem, String attName,
boolean mandatory) throws SAXException {
String value = getAttribute(elem, attName, mandatory);
return Boolean.valueOf(value).booleanValue();
}
/**
* getChildText purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child text value
* of the specified element name.
* </p>
*
* @param root The root element to look for children in.
* @param childName The name of the attribute to look for.
*
* @return The value if the child was found, the null otherwise.
*/
public static String getChildText(Element root, String childName) {
try {
return getChildText(root, childName, false);
} catch (SAXException ex) {
return null;
}
}
/**
* getChildText purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child text value
* of the specified element name. An exception occurs when the node is
* required and not found.
* </p>
*
* @param root The root element to look for children in.
* @param childName The name of the attribute to look for.
* @param mandatory true when an exception should be thrown if the text
* does not exist.
*
* @return The value if the child was found, the null otherwise.
*
* @throws SAXException When a child attribute is required and not found.
*/
public static String getChildText(Element root, String childName,
boolean mandatory) throws SAXException {
Element elem = getChildElement(root, childName, mandatory);
if (elem != null) {
return getElementText(elem, mandatory);
} else {
if (mandatory) {
String msg = "Mandatory child " + childName + "not found in "
+ " element: " + root;
throw new SAXException(msg);
}
return null;
}
}
/**
* getChildText purpose.
*
* <p>
* Used to help with XML manipulations. Returns the text value of the
* specified element name.
* </p>
*
* @param elem The root element to look for children in.
*
* @return The value if the text was found, the null otherwise.
*/
public static String getElementText(Element elem) {
try {
return getElementText(elem, false);
} catch (SAXException ex) {
return null;
}
}
/**
* getChildText purpose.
*
* <p>
* Used to help with XML manipulations. Returns the text value of the
* specified element name. An exception occurs when the node is required
* and not found.
* </p>
*
* @param elem The root element to look for children in.
* @param mandatory true when an exception should be thrown if the text
* does not exist.
*
* @return The value if the text was found, the null otherwise.
*
* @throws SAXException When text is required and not found.
*/
public static String getElementText(Element elem, boolean mandatory)
throws SAXException {
String value = null;
LOGGER.finest("getting element text for " + elem);
if (elem != null) {
Node child;
NodeList childs = elem.getChildNodes();
int nChilds = childs.getLength();
for (int i = 0; i < nChilds; i++) {
child = childs.item(i);
if (child.getNodeType() == Node.TEXT_NODE) {
value = child.getNodeValue();
if (mandatory && "".equals(value.trim())) {
throw new SAXException(elem.getNodeName()
+ " text is empty");
}
break;
}
}
if (mandatory && (value == null)) {
throw new SAXException(elem.getNodeName()
+ " element does not contains text");
}
} else {
throw new SAXException("Argument element can't be null");
}
return value;
}
/**
* getKeyWords purpose.
*
* <p>
* Used to help with XML manipulations. Returns a list of keywords that
* were found.
* </p>
*
* @param keywordsElem The root element to look for children in.
*
* @return The list of keywords that were found.
*/
public static String[] getKeyWords(Element keywordsElem) {
NodeList klist = keywordsElem.getElementsByTagName("keyword");
int kCount = klist.getLength();
List keywords = new ArrayList(kCount);
String kword;
Element kelem;
for (int i = 0; i < kCount; i++) {
kelem = (Element) klist.item(i);
kword = getElementText(kelem);
if (kword != null) {
keywords.add(kword);
}
}
Object[] s = (Object[]) keywords.toArray();
if (s == null) {
return new String[0];
}
String[] ss = new String[s.length];
for (int i = 0; i < ss.length; i++)
ss[i] = s[i].toString();
return ss;
}
/**
* getFirstChildElement purpose.
*
* <p>
* Used to help with XML manipulations. Returns the element which
* represents the first child.
* </p>
*
* @param root The root element to look for children in.
*
* @return The element if a child was found, the null otherwise.
*/
public static Element getFirstChildElement(Element root) {
Node child = root.getFirstChild();
while (child != null) {
if (child.getNodeType() == Node.ELEMENT_NODE) {
return (Element) child;
}
child = child.getNextSibling();
}
return null;
}
/**
* getDoubleAttribute purpose.
*
* <p>
* Used to help with XML manipulations. Returns the first child integer
* attribute of the specified name. An exception occurs when the node is
* required and not found.
* </p>
*
* @param elem The root element to look for children in.
* @param attName The name of the attribute to look for.
* @param mandatory true when an exception should be thrown if the
* attribute element does not exist.
*
* @return The double value if the attribute was found, the NaN otherwise.
*
* @throws SAXException When a attribute element is required and not found.
*/
public static double getDoubleAttribute(Element elem, String attName,
boolean mandatory) throws SAXException {
String value = getAttribute(elem, attName, mandatory);
double d = Double.NaN;
if (value != null) {
try {
d = Double.parseDouble(value);
} catch (NumberFormatException ex) {
throw new SAXException("Illegal attribute value for " + attName
+ " in element " + elem.getNodeName()
+ ". Expected double, but was " + value);
}
}
return d;
}
}