/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package xml.parse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URLDecoder;
import java.util.Enumeration;
import javax.xml.stream.events.Attribute;
import java.util.Properties;
import javax.xml.namespace.QName;
import javax.xml.stream.EventFilter;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
/**
* Class to parse configuration properties and serve values in required format
*
* @author Nageswara Rao. V
*/
public class ConfigUtil implements IConfig {
String filePath; // Path of configuration file
String[] types; // list of types to parse, will be left null to skip type filter
String[] tags; //list of tags to parse, will be left null to handle all tags
Properties props = new Properties();
/**
* Constructor to initialize configuration utility
*
* @param filePath - Path to configuration file
* @param types - array of types to filter
*/
public ConfigUtil(String filePath, String[] propTags, String[] types) {
this.filePath = filePath;
this.types = types;
this.tags = propTags;
loadConfig();
}
/**
* Overloaded Constructor to skip type filter
*
* @param filePath - Path to configuration file
* @param propTags - array of tags to handle
*/
public ConfigUtil(String filePath, String[] propTags) {
this(filePath, propTags, null);
}
/**
* Overloaded Constructor to skip type filter handle all tags declared
*
* @param filePath - Path to configuration file
* @param propTags - array of tags to handle
*/
public ConfigUtil(String filePath) {
this(filePath, null, null);
}
/**
* Method to load and parse properties and populates props object
*/
private void loadConfig() {
try {
XMLConfigParser parser = new XMLConfigParser(filePath);
parser.setTagFilter(tags);
parser.setTypeFilter(types);
props = parser.parseProps();
} catch (ConfigException cExp) {
System.out.println("Failed to parse config file. Return values will be default values");
}
}
/**
*
* @return - Current configuration
*/
public Properties getConfig() {
return props;
}
/**
* To returns integer value
*
* @param key - property key
* @param def - default integer value
* @return - integer value
*/
public int getIntegerValue(String key, int def) {
String value = props.getProperty(key);
try {
return Integer.parseInt(value);
} catch (Exception numfExp) {
System.out.println("Invalid integer "+value);
}
return def;
}
/**
* To return String value
*
* @param key - Property key
* @param def - default string value
* @return - string value
*/
public String getValue(String key, String def) {
String value = props.getProperty(key);
if (value == null) {
return def;
}
return value;
}
/**
* To return double value
*
* @param key - Property key
* @param def - default double value
* @return - double value
*/
public double getDoubleValue(String key, double def) {
String value = props.getProperty(key);
try {
return Double.parseDouble(value);
} catch (Exception numfExp) {
System.out.println("Invalid double "+value);
}
return def;
}
/**
* To return long value
*
* @param key - property key
* @param def - default long value
* @return - long value
*/
public long getLongValue(String key, long def) {
String value = props.getProperty(key);
try {
return Long.parseLong(value);
} catch (Exception numfExp) {
System.out.println("Invalid long "+value);
}
return def;
}
/**
* To return double value
*
* @param key - Property key
* @param def - default double value
* @return - double value
*/
public float getFloatValue(String key, float def) {
String value = props.getProperty(key);
try {
return Float.parseFloat(value);
} catch (Exception numfExp) {
System.out.println("Invalid float "+value);
}
return def;
}
/**
* Class to parse and extract configurations from xml file
*/
class XMLConfigParser {
private final String ATTR_TYPE = "TYPE"; // Identifier of TYPE attribute
private final String ATTR_KEY = "KEY"; // Identifier of KEY attribute
private final String ATTR_VALUE = "VALUE"; // Identifier of VALUE attribute
String[] typeFilters = new String[0];
String[] tagFilters = new String[0];
File configFile; // configuration file object
Properties configProps = new Properties();
/**
* Constructor to initialize XML StAX Parser with the given configuration
* file written in well formed xml format
*
* @param filePath - path to configuration xml
* @throws ConfigException
*/
public XMLConfigParser(String filePath) throws ConfigException {
this.configFile = loadFile(filePath);
}
/**
* Method to validate and load configuration file
*
* @param filePath - file path
* @return - File object if the path locates valid configuration xml
* @throws ConfigException
*/
private File loadFile(String filePath) throws ConfigException {
File configFile = null;
filePath = URLDecoder.decode(filePath);
if ((filePath != null) && (configFile = new File(filePath)).exists() && configFile.isFile()) {
return configFile;
} else {
throw new ConfigException("Invalid config file : "+filePath, null);
}
}
/**
* Method to set tags that needs to pay attention
*
* @param tags - array of tags
*/
public void setTagFilter(String[] tags) {
if(tags != null) {
this.tagFilters = tags;
}
}
/**
* Method to set attributes that needs to pay attention
*
* @param tags - array of attributes
*/
public void setTypeFilter(String[] attrs) {
if(attrs != null) {
this.typeFilters = attrs;
}
}
/**
* Parse and extract attributes in <PROP> tag, enforce if filter is defined
*
* @throws ConfigException
*/
public Properties parseProps() throws ConfigException {
XMLEventReader reader = getReader();
if(typeFilters == null || typeFilters.length == 0) {
parseAttributes(reader);
} else {
parseFilteredAttributes(reader);
}
return configProps;
}
/**
* Method to key/value from filtered types
*
* @param reader - StAX reader to run through the document
* @throws ConfigException
*/
private void parseFilteredAttributes(XMLEventReader reader) throws ConfigException {
while(reader.hasNext()) {
StartElement startElement = null;
if((startElement = getStartElement(reader)) != null) {
Attribute attr = startElement.getAttributeByName(new QName(ATTR_TYPE));
if(attr != null && acceptAttribute(attr)) {
extractProperty(startElement);
}
}
}
}
private boolean acceptAttribute(Attribute attr) {
String value = attr.getValue();
for(int indx = 0; indx < typeFilters.length; indx++) {
if(typeFilters[indx].equalsIgnoreCase(value)) {
return true;
}
}
return false;
}
/**
* Method to parse key/value from all <PROP> tags
*
* @param reader - StAX reader to run through the document
* @param TAG_NAME - Tag name to handle
* @throws ConfigException
*/
private void parseAttributes(XMLEventReader reader) throws ConfigException {
while(reader.hasNext()) {
StartElement startElement = null;
if((startElement = getStartElement(reader)) != null) {
extractProperty(startElement);
}
}
}
private StartElement getStartElement(XMLEventReader reader) throws ConfigException {
StartElement startElement = null;
try {
XMLEvent event = reader.nextEvent();
if(event.isStartElement()) {
startElement = event.asStartElement();
}
} catch (XMLStreamException xmlStrmExp) {
throw new ConfigException("Exception while reading next event", xmlStrmExp);
}
return startElement;
}
/**
* Method to extract key/value from tag
*
* @param startElement - Element to parse
*/
private void extractProperty(StartElement startElement) {
Attribute keyAttr = startElement.getAttributeByName(new QName(ATTR_KEY));
if(keyAttr == null) {
return;
}
String key = keyAttr.getValue();
String value = startElement.getAttributeByName(new QName(ATTR_VALUE)).getValue();
if(key != null) {
configProps.put(key, value);
}
}
/**
* Method to construct StAX reader to parse the xml
*
* @return - Handle to reader
* @throws ConfigException
*/
private XMLEventReader getReader() throws ConfigException {
XMLEventReader parser = null;
try {
FileInputStream inStream = new FileInputStream(configFile);
XMLInputFactory factory = XMLInputFactory.newInstance();
parser = factory.createXMLEventReader(inStream);
parser = factory.createFilteredReader(parser, new PropEventFilter(tagFilters));
} catch (FileNotFoundException fnfExp) {
throw new ConfigException("Invalid Config file", fnfExp);
} catch (XMLStreamException xmlSExp) {
throw new ConfigException("Invalid config format", xmlSExp);
}
return parser;
}
}
/**
* Class to filter meta and only the filtered tags from xml document
*/
class PropEventFilter implements EventFilter {
String[] tagFilters = new String[0];
PropEventFilter() {
}
PropEventFilter(String[] tagFilters) {
this.tagFilters = tagFilters;
}
public boolean accept(XMLEvent event) {
return doAccept(event);
}
private boolean doAccept(XMLEvent event) {
// Exclude PIs
if(event.isProcessingInstruction()) {
return false;
} else if (tagFilters.length > 0) {
// filter tag if set
boolean accept = false;
StartElement startElement = null;
if(event.isStartElement()) {
startElement = event.asStartElement();
String tag = startElement.getName().toString();
for(int idx = 0; idx < tagFilters.length; idx++) {
if(tag.equalsIgnoreCase(tagFilters[idx])) {
accept = true;
break;
}
}
}
return accept;
}
return true;
}
}
/**
*
* Class to handle exceptions while parsing
*/
class ConfigException extends Exception {
String message;
public ConfigException(String message, Throwable exp) {
super(exp);
this.message = message;
}
public String getMessage() {
return message;
}
}
public static void main(String args[]) {
try {
System.out.println("With types");
String[] types = {"person", "address", "employment"};
String[] tags = {"PROP"};
ConfigUtil cfgUtil = new ConfigUtil("D:\\ws\\algorithms\\algorithms\\config.xml",
tags, types);
System.out.println("Name : "+cfgUtil.getValue("name", "Default Value"));
System.out.println("Sal : "+cfgUtil.getIntegerValue("age", 25));
System.out.println("double : "+cfgUtil.getDoubleValue("salary", 25));
System.out.println("General accessor");
Properties props = cfgUtil.getConfig();
Enumeration enumrt = props.keys();
while(enumrt.hasMoreElements()) {
String name = (String)enumrt.nextElement();
String value = (String)props.getProperty(name);
System.out.println("Name : "+name+ " Value : "+value);
}
} catch (Exception exp) {
exp.printStackTrace();
System.out.println("Exception "+exp.getMessage());
}
}
}
/*---- Sample configuration ---*/
<?xml version="1.0" encoding="UTF-8"?>
<!--
Document : config.xml
Created on : May 23, 2011, 12:53 PM
Author : Nageswara Rao. V
Description:
Purpose of the document follows.
-->
<CONFIG>
<PROP TYPE="person" KEY="name" VALUE="RAO"/>
<PROP TYPE="person" KEY="age" VALUE="30"/>
<PROP TYPE="person" KEY="height" VALUE="177"/>
<PROP TYPE="employment" KEY="salary" VALUE="4550.00"/>
<PROP TYPE="employment" KEY="firm" VALUE="ABC Inc."/>
<PROP TYPE="address" KEY="dno" VALUE="170"/>
<PROP TYPE="address" KEY="street" VALUE="AS Puram"/>
<PROP TYPE="address" KEY="city" VALUE="Chennai"/>
</CONFIG>