/** * '$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() {} }; }