/**
* '$RCSfile: XMLProperties.java,v $'
* Copyright: 2000 Regents of the University of California
* Authors: @authors@
* Release: @release@
*
* '$Author: daigle $'
* '$Date: 2008-07-07 04:27:27 $'
* '$Revision: 1.6 $'
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the above
* copyright notice and the following two paragraphs appear in all copies
* of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
* FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
* THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
* PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
* CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package edu.ucsb.nceas.utilities;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Iterator;
import javax.swing.JOptionPane;
import javax.xml.transform.TransformerException;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
//import org.apache.log4j.Logger;
/**
* This class is designed to retrieve and store String
properties
* information in an XML file. The concept is similar to that of a Properties
* file except that using the XML format allows for a hierarchy of properties
* and repeated properties.
*
* All 'keys' are XPath expressions defining element names, while values are
* always stored as XML text nodes. The XML file is parsed and stored in memory
* as a DOM object.
*/
public class XMLProperties
{
/**
* root node of the in-memory DOM structure
*/
private Node root;
/**
* Document node of the in-memory DOM structure
*/
private Document doc;
/**
* XML file used to store properties
*/
private File xmlPropsFile;
/**
* XML input stream used to retrieve properties
*/
private InputStream xmlPropsSource;
//output format used by store() method
private static String OUTPUT_FORMAT = "UTF-8";
// private static Logger log = Logger.getLogger(XMLProperties.class.getName());
/**
* Creates a new, empty XML properties object
*/
public XMLProperties() {}
/**
* Reads properties from the XML input stream.
*
* @param xmlPropsFile File
from which the properties
* XML is to be read and parsed
*
* @throws IOException if File cannot be opened or processed
*/
public void load(File xmlPropsFile) throws IOException {
this.xmlPropsFile = xmlPropsFile;
InputStream xmlPropsSource = new FileInputStream(xmlPropsFile);
this.load(xmlPropsSource);
}
/**
* Reads properties from the XML input stream.
*
* @param xmlPropsSource InputStream
from which the properties
* XML is to be read and parsed
*
* @throws IOException if InputStream cannot be opened or processed
*/
public void load(InputStream xmlPropsSource) throws IOException {
this.xmlPropsSource = xmlPropsSource;
init(xmlPropsSource);
}
private void init(InputStream xmlPropsSource) throws IOException {
Reader sr = new InputStreamReader(xmlPropsSource);
root = XMLUtilities.getXMLReaderAsDOMTreeRootNode(sr);
}
/**
* Gets the value corresponding to an xpath key string
*
* @param keyXPath XPath pointing to an element or elements, each of which
* may contain a single string value, but no additional
* non-text elements
*
* @return an array of strings containing the retrieved values, or
* null if no values retrieved
*
* @throws javax.xml.transform.TransformerException
if there is
* a problem executing the XPATH expression
*/
private final StringBuffer propResultBuff = new StringBuffer();
//
public String[] getProperty(String keyXPath) throws TransformerException {
NodeList nl = XMLUtilities.getNodeListWithXPath(root, keyXPath);
// log.debug(
// "XMLProperties.getProperty(): getNodeListWithXPath() returned NodeList: "
// +nl);
if (nl==null) {
// log.debug(
// "XMLProperties.getProperty(): getNodeListWithXPath() returned NULL");
return null;
}
int totChildren = nl.getLength();
if (totChildren < 1) {
// log.debug( "XMLProperties.getProperty(): getNodeListWithXPath() returned "
// +totChildren+" children; returning new String[0]");
return null;
}
// log.debug( "XMLProperties.getProperty(): getNodeListWithXPath() returned "
// +totChildren+" children");
List resultList = new ArrayList();
Node nextChild = null;
for (int i = 0; i < nl.getLength(); i++) {
NodeList cnl = nl.item(i).getChildNodes();
if (cnl==null || cnl.getLength() < 1) continue;
propResultBuff.delete(0, propResultBuff.length());
for (int ci = 0; ci < cnl.getLength(); ci++) {
nextChild = cnl.item(ci);
if (nextChild.getNodeType() == Node.TEXT_NODE
|| nextChild.getNodeType() == Node.CDATA_SECTION_NODE) {
propResultBuff.append(nextChild.getNodeValue().trim());
}
}
resultList.add(propResultBuff.toString());
}
return (String[])(resultList.toArray(new String[resultList.size()]));
}
/**
* used to set a value corresponding to 'key'; value is changed in DOM
* structure in memory. Returns the previous String
value for
* this parameter, or null if it didn't exist
*
* @param key the xpath identifying the element name.
* @param value new value to be inserted in ith key
* @return the previous String
value for this parameter, or null
* if it didn't exist
* @throws TransformerException
*/
public String setProperty(String key, String value)
throws TransformerException {
String[] resultArray = getProperty(key);
XMLUtilities.addTextNodeToDOMTree(root, key, value);
return (resultArray!=null)? resultArray[0] : null;
}
/**
* Writes this property XML DOM to the original location in XML format.
* The stream is written using UTF-8 character encoding.
* After the entries have been written, the output stream is flushed and
* closed.
*
* @throws IOException if original file cannot be found or written to
*/
public void store() throws IOException {
FileOutputStream out = null;
if (xmlPropsFile==null) {
throw new IOException(
"Cannot find properties file - xmlPropsFile==null");
} else if (!xmlPropsFile.canWrite()) {
throw new IOException(
"Cannot write to properties file (xmlPropsFile.canWrite() is false): "
+ xmlPropsFile.getName());
} else {
try {
out = new FileOutputStream(xmlPropsFile);
store(out);
} finally {
if (out != null) {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* Writes this property XML DOM to the output stream in XML format, suitable
* for loading into a Properties object using the load method. The stream is
* written using the UTF-8 character encoding.
* After the entries have been written, the output stream is flushed. The
* output stream remains open after this method returns.
*
* @param out the OutputStream
to which the output will be
* written
*/
public void store(OutputStream out) {
// out.println("");
PrintWriter pw = new PrintWriter(out, true);
this.list(pw);
}
/**
* Prints this property list out to the specified output stream. This method
* is useful for debugging.
*
* @param out PrintWriter
*/
public void list(PrintWriter out) {
XMLUtilities.print(root, out, OUTPUT_FORMAT);
}
/**
* Prints this property list out to the specified output stream. This method
* is useful for debugging.
*
* @param out PrintStream
*/
public void list(PrintStream out) {
this.store(out);
}
/**
* Returns an enumeration of all the XPath keys in this properties object
*
* @return Iterator
*/
public Iterator propertyNames() {
OrderedMap nvpMap = XMLUtilities.getDOMTreeAsXPathMap(root);
if (nvpMap==null) return emptyIterator;
Set nvpSet = nvpMap.keySet();
if (nvpSet==null) return emptyIterator;
return nvpSet.iterator();
}
// an empty class implementing the Iterator interface
private Iterator emptyIterator = new Iterator() {
public boolean hasNext() { return false; }
public Object next() { return null; }
public void remove() {}
};
}