Skip to content

Instantly share code, notes, and snippets.

@theresajayne
Created September 1, 2011 08:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theresajayne/1185736 to your computer and use it in GitHub Desktop.
Save theresajayne/1185736 to your computer and use it in GitHub Desktop.
package uk.co.mycomp.utilities;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This class automatically finds, loads and caches properties files from the
* Java class path.
*/
public final class CachedTypedProperties extends TypedProperties {
/**
*
*/
private static final long serialVersionUID = 6777958049074939398L;
/**
* The flush parameter to use to specify which properties to flush
*/
public static final String FLUSH_PROPERTIES_NAME = "properties"; //NOPMD - reviewed theresa.forster
/**
* The singletons -- one per properties file
*/
private static Map<String, Object> instances = Collections.synchronizedMap(new HashMap<String, Object>());
/**
* Singletons require private constructors
*/
private CachedTypedProperties() {
super();
}
/**
* Get an instance, cached if possible
*
* @param name the name of the properties file for which to get an instance
* of this class
* @return an instance of this class for the specified properties file --
* only newly instantiated the first time this method is called
* @throws ClassNotFoundException if the properties file could not be found
*/
public static synchronized CachedTypedProperties getInstance(final String name)throws ClassNotFoundException //NOPMD - reviewed theresa.forster
{
CachedTypedProperties propertiesToReturn = null;
final Object propertyCheck = CachedTypedProperties.instances.get(name);
if(propertyCheck instanceof CachedTypedProperties)
{
propertiesToReturn = (CachedTypedProperties)propertyCheck;
}
else if (propertyCheck!= null)
{
throw new ClassNotFoundException(String.format("Could not find %s file in Java class path: %s", name,System.getProperty("java.class.path")));
}
if (null == propertiesToReturn) {
propertiesToReturn = new CachedTypedProperties();
try {
//
// This loads the requested properties file from the Java class path
//
propertiesToReturn.load(
propertiesToReturn.getClass().getClassLoader().getResourceAsStream(
name
)
);
}
catch (NullPointerException npe){
throw new ClassNotFoundException(
"Could not find " + name + " file in Java class path: " +
System.getProperty("java.class.path"), npe);
}
catch (IOException ioe) {
throw new ClassNotFoundException(
"Error while reading " + name + " file", ioe
);
}
CachedTypedProperties.instances.put(name, propertiesToReturn);
}
return propertiesToReturn;
}
/**
* Get an instance of an XML configuration document, cached if possible
*
* @param name the name of the properties file for which to get an instance
* of this class
* @param orgId the organisation id within the XML config file to get
* @return an instance of this class for the specified properties file --
* only newly instantiated the first time this method is called
* @throws ClassNotFoundException if the properties file could not be found
*/
@SuppressWarnings("unchecked")
public static synchronized CachedTypedProperties getInstance(final String name,final int orgId) throws ClassNotFoundException
{
CachedTypedProperties returnValue = null;
final Object propertyCheck = CachedTypedProperties.instances.get(name);
if(propertyCheck instanceof Map)
{
final Map <String,CachedTypedProperties> XMLMap = (Map<String,CachedTypedProperties>)propertyCheck;
returnValue = XMLMap.get(String.valueOf(orgId));
}
else if (propertyCheck!= null)
{
throw new ClassNotFoundException(String.format("Could not find %s file in Java class path: %s", name,System.getProperty("java.class.path")));
}
if (null == returnValue) {
returnValue = new CachedTypedProperties();
try {
loadXMLProperties(name);
//now having reloaded all the contained entries we need to reset the property block to the
//one we wanted in the first place
final Map<String, CachedTypedProperties> xmlProps = (Map<String, CachedTypedProperties>)CachedTypedProperties.instances.get(name);
returnValue = CachedTypedProperties.class.cast(xmlProps.get(String.valueOf(orgId)));
//propertiesToReturn = (CachedTypedProperties)((HashMap)CachedTypedProperties.instances.get(name)).get(orgId);
}
catch (DOMException de)
{
throw new ClassNotFoundException(
"DOMException in XML config file " + name + " in Java class path: " +
System.getProperty("java.class.path"), de );
}
catch (Exception e)
{
throw new ClassNotFoundException("XML conversion error " + name + " file", e);
}
}
return returnValue;
}
/**
* Returns the Hashmap of multiple configuration property files
* @param name
* @return
*/
public static Set<String> getInstancesKeys(final String name)throws ClassNotFoundException
{
return ((Map<String,CachedTypedProperties>)getInstances(name)).keySet();
}
/**
* Returns the Hashmap of multiple configuration property files
* @param name
* @return
*/
@SuppressWarnings("unchecked")
public static synchronized Map<String,CachedTypedProperties> getInstances(final String name)throws ClassNotFoundException
{
Map<String,CachedTypedProperties> returnValue = null;
try
{
final Object propertyCheck = CachedTypedProperties.instances.get(name);
if(propertyCheck instanceof Map)
{
returnValue = (Map<String,CachedTypedProperties>)propertyCheck;
}
else if (propertyCheck!= null)
{
throw new ClassNotFoundException(String.format("Could not find %s file in Java class path: %s", name,System.getProperty("java.class.path")));
}
if (null == returnValue)
{
loadXMLProperties(name);
//now having reloaded all the contained entries we need to reset the property block to the
//one we wanted in the first place
returnValue= (Map<String, CachedTypedProperties>)CachedTypedProperties.instances.get(name);
//propertiesToReturn = (CachedTypedProperties)((HashMap)CachedTypedProperties.instances.get(name)).get(orgId);
}
}
catch (DOMException de)
{
throw new ClassNotFoundException(
"Could not parse input XML file " + name + " in Java class path: " +
System.getProperty("java.class.path"), de );
}
catch (Exception e)
{
throw new ClassNotFoundException("XML conversion error " + name + " file", e);
}
return returnValue;
}
/**
* Get an instance, cached if possible
*
* @param url the url of the properties file
* @return an instance of this class for the specified properties file --
* only newly instantiated the first time this method is called
* @throws Exception
*/
public static synchronized CachedTypedProperties getInstance(final URL url) throws ClassNotFoundException {
CachedTypedProperties returnValue = null;
final Object propertyCheck = CachedTypedProperties.instances.get(url.getPath());
if(propertyCheck instanceof CachedTypedProperties|| propertyCheck==null)
{
returnValue = (CachedTypedProperties)propertyCheck;
}
else
{
throw new ClassNotFoundException(
"Could not find " + url + " file in Java class path: " +
System.getProperty("java.class.path"));
}
if(url != null) { //NOPMD - reviewed theresa.forster
if (null == returnValue) {
returnValue = new CachedTypedProperties();
InputStream inputStream = null;
try {
inputStream = url.openStream();
//
// This loads the requested properties file from the Java class path
//
returnValue.load(inputStream);
}
catch (IOException ioe)
{
throw new ClassNotFoundException(
"Error while reading property URL " + url , ioe
);
}
finally {
if(inputStream != null) {
try
{
inputStream.close();
}
catch (IOException ioe)
{
//This one we shouldn't throw on so just ignore
}
}
}
CachedTypedProperties.instances.put(url.getPath(), returnValue);
}
} else {
throw new ClassNotFoundException("URL passed in was NULL.");
}
return returnValue;
}
/**
* Wipes all of the cached properties
*/
public static void flushData() {
instances.clear();
}
/**
* Removed the properties identified by the {@value #FLUSH_PROPERTIES_NAME} property
* @param flushParameters the collection of parameters
*/
public static void flushData(final Properties flushParameters) {
final String propertiesName = flushParameters.getProperty(FLUSH_PROPERTIES_NAME);
if (null != propertiesName) {
instances.remove(propertiesName);
}
}
private static ByteArrayOutputStream processXMLProperties(NodeList inputNodes,final DocumentBuilder docBuild) throws ClassNotFoundException
{
ByteArrayOutputStream outStream;
final Element tmpElem = (Element)inputNodes.item(0).cloneNode(true);
final Document tmpDoc2 = docBuild.newDocument();
tmpDoc2.adoptNode(tmpElem);
tmpDoc2.appendChild(tmpElem);
tmpDoc2.normalize();
try
{
XMLUtils.convertXmlDocToString(tmpDoc2);
final Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://java.sun.com/dtd/properties.dtd");
outStream = new ByteArrayOutputStream(); //NOPMD - reviewed theresa.forster
trans.transform(new DOMSource(tmpDoc2), new StreamResult(outStream)); //NOPMD - reviewed theresa.forster
}
catch (Exception e)
{
throw new ClassNotFoundException("Error in processXMLProperties",e);
}
return outStream;
}
@SuppressWarnings("unchecked")
private static Map<String, CachedTypedProperties> loadXMLProperties(String name) throws ClassNotFoundException
{
try {
//
// This loads the requested properties file from the Java class path
// parses it and stores the contents in the system.
//
CachedTypedProperties tempProp = new CachedTypedProperties();
final Map <String,CachedTypedProperties> XMLMap = new HashMap<String,CachedTypedProperties>();
final File filePointer = new File(tempProp.getClass().getClassLoader().getResource(name).getPath()); //NOPMD - reviewed theresa.forster
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder docBuild = dbf.newDocumentBuilder();
final Document doc = docBuild.parse(filePointer);
final NodeList nodelist = doc.getElementsByTagName("client");
for(int a = 0; a<nodelist.getLength();a++)
{
final Element tmpElement = (Element)nodelist.item(a);
final String tmpOrgId = tmpElement.getAttribute("organisation");
//This gets the child nodes which should be the property nodes inside the XML
final NodeList tmpNodes2 = tmpElement.getElementsByTagName(FLUSH_PROPERTIES_NAME);
if(tmpNodes2.getLength() !=0)
{
tempProp = new CachedTypedProperties();
tempProp.loadFromXML(new ByteArrayInputStream(processXMLProperties(tmpNodes2,docBuild).toByteArray()));
XMLMap.put(String.valueOf(tmpOrgId), tempProp);
}
}
CachedTypedProperties.instances.put(name, XMLMap);
//now having reloaded all the contained entries we need to reset the property block to the
//one we wanted in the first place
final Map<String, CachedTypedProperties> xmlProps = (Map<String, CachedTypedProperties>)CachedTypedProperties.instances.get(name);
return xmlProps;
//propertiesToReturn = (CachedTypedProperties)((HashMap)CachedTypedProperties.instances.get(name)).get(orgId);
}
catch (DOMException de)
{
throw new ClassNotFoundException(
"DOMException in XML config file " + name + " in Java class path: " +
System.getProperty("java.class.path"), de );
}
catch (SAXException se)
{
throw new ClassNotFoundException(
"SAXException in XML config file " + name + " in Java class path: " +
System.getProperty("java.class.path"), se );
}
catch (ParserConfigurationException pce)
{
throw new ClassNotFoundException(
"Could not create XML parser for " + name + " file in Java class path: " +
System.getProperty("java.class.path"), pce );
}
catch (IOException ioe) {
throw new ClassNotFoundException(
"Error while reading " + name + " file", ioe
);
}
catch (Exception e)
{
throw new ClassNotFoundException("XML conversion error " + name + " file", e);
}
}
}
----------------------------------- TypedProperties
package uk.co.mycomp.utilities;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* Extends properties to implement parsing for types other than String.
*/
public class TypedProperties extends java.util.Properties {
/**
*
*/
private static final long serialVersionUID = 251439833803960676L;
/**
* Read a required string
*
* @param propertyName name of the property to read
* @return the value of the property
* @throws NullPointerException if the property is not present
*/
public String getStringProperty(String propertyName) {
String returnValue = this.getProperty(propertyName);
if (null == returnValue) {
throw new NullPointerException("Parameter " + propertyName +
" not defined!");
}
return returnValue;
}
/**
* Read a defaultable string
*
* @param propertyName name of the property to read
* @param defaultValue default value to use if property not set
* @return the value of the property or the default value if it is not set
*/
public String getStringProperty(String propertyName, String defaultValue) {
return this.getProperty(propertyName, defaultValue);
}
/**
* Read a required integer
*
* @param propertyName name of the property to read
* @return the parsed value of the property
* @throws NumberFormatException if the property cannot be parsed
* @throws NullPointerException if the property is not present
*/
public int getIntProperty(String propertyName) {
String readVal = this.getProperty(propertyName);
return Integer.parseInt((readVal != null ? readVal.trim() : readVal));
}
/**
* Read a defaultable integer
*
* @param propertyName name of the property to read
* @param defaultValue default value to use if property not set
* @return the parsed value of the property or the default value if it is not
* set
* @throws NumberFormatException if the property cannot be parsed
*/
public int getIntProperty(String propertyName,
int defaultValue) {
int returnValue;
String readValue = this.getProperty(propertyName);
if (null == readValue) {
returnValue = defaultValue;
} else {
returnValue = Integer.parseInt(readValue.trim());
}
return returnValue;
}
/**
* Retrieves a list of integer objects from a properties file, where the entry is a comma
* delimeted list ie 12555,12565
* @param propertyName
* @return
*/
public List<Integer> getDelimetedIntProperty(String propertyName, String delimeter) {
List<Integer> list = new ArrayList<Integer>();
List<String> strList = getDelimetedProperty(propertyName, delimeter);
for (String str : strList) {
try {
list.add(Integer.parseInt(str));
} catch (NumberFormatException e) {
// Do Nothing
}
}
return list;
}
/**
* Retrieves a list of integer objects from a properties file, where the entry is a comma
* delimeted list ie 12555,12565
* @param propertyName
* @return
*/
public List<String> getDelimetedProperty(String propertyName, String delimeter) {
List<String> list = new ArrayList<String>();
//Test if there is a value
String rawValue = this.getProperty(propertyName);
if (StringUtils.isNullOrEmpty(rawValue)) {
return list;
}
StringTokenizer st = new StringTokenizer(rawValue, delimeter);
while (st.hasMoreTokens()) {
String token = st.nextToken();
list.add(token.trim());
}
return list;
}
/**
* Read a required boolean
*
* @param propertyName name of the property to read
* @return the parsed value of the property
* @throws NullPointerException if the property is not present
*/
public boolean getBooleanProperty(String propertyName) {
String readVal = this.getProperty(propertyName);
return (Boolean.valueOf((readVal != null ? readVal.trim() : readVal))).booleanValue();
}
/**
* Read a defaultable boolean
*
* @param propertyName name of the property to read
* @param defaultValue default value to use if property not set
* @return the parsed value of the property or the default value if it is not
* set
*/
public boolean getBooleanProperty(String propertyName,
boolean defaultValue) {
boolean returnValue;
String readValue = this.getProperty(propertyName);
if (null == readValue) {
returnValue = defaultValue;
} else {
returnValue = (Boolean.valueOf(readValue.trim())).booleanValue();
}
return returnValue;
}
/**
* Read a required long
*
* @param propertyName name of the property to read
* @return the parsed value of the property
* @throws NumberFormatException if the property cannot be parsed
* @throws NullPointerException if the property is not present
*/
public long getLongProperty(String propertyName) {
String readVal = this.getProperty(propertyName);
return Long.parseLong((readVal != null ? readVal.trim() : readVal));
}
/**
* Read a defaultable long
*
* @param propertyName name of the property to read
* @param defaultValue default value to use if property not set
* @return the parsed value of the property or the default value if it is not
* set
* @throws NumberFormatException if the property cannot be parsed
*/
public long getLongProperty(String propertyName,
long defaultValue) {
long returnValue;
String readValue = this.getProperty(propertyName);
if (null == readValue) {
returnValue = defaultValue;
} else {
returnValue = Long.parseLong(readValue.trim());
}
return returnValue;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment