/*
* PropertyContext.java
* Copyright 2009 Connor Petty <cpmeister@users.sourceforge.net>
*
* 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Created on Sep 4, 2009, 8:21:08 PM
*/
package pcgen.system;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
/**
* This class acts similarly to the Properties class but behaves defferntly
* in that SubContexts can be created. These SubContexts share the properties
* of its parent but they use a different namespace than the parent when
* a property is set. The root parent contains all the properties of its
* children and likewise, all of the properties of the children can be edited
* from the root parent. In child contexts, the properties of all other children
* that share its ancestors are visible but only that child's namespace is editable.
* It is considered bad practice to look at the other siblings properties from within
* a child.
* @author Connor Petty <cpmeister@users.sourceforge.net>
*/
public class PropertyContext implements PropertyChangeListener
{
protected final Properties properties;
protected final PropertyContext parent;
protected final PropertyChangeSupport support;
protected final String name;
protected PropertyContext(String name)
{
this(name, null);
}
protected PropertyContext(String name, PropertyContext parent)
{
this.name = name;
this.support = new PropertyChangeSupport(this);
this.parent = parent;
this.properties = (parent == null) ? new Properties() : parent.properties;
}
/**
* Create a new PropertyContext with a supplied properties object. As
* the property object is supplied, it is expected that the parent will
* normally be null.
*
* @param name The filename of the context. Normally ends in .ini
* @param parent The parent context, normally null
* @param properties The properties object to be used.
*/
protected PropertyContext(String name, PropertyContext parent, Properties properties)
{
this.name = name;
this.support = new PropertyChangeSupport(this);
this.parent = parent;
this.properties = properties;
}
public String getName()
{
return name;
}
public PropertyContext createChildContext(String name)
{
return new PropertyContext(name, this);
}
public void addPropertyChangeListener(PropertyChangeListener listener)
{
support.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String property, PropertyChangeListener listener)
{
support.addPropertyChangeListener(property, listener);
}
/**
* Searches for the property with the specified key in this property context.
* The method returns {@code null} if the property is not found.
*
* @param key the property key.
* @return the value in this property context with the specified key value.
*/
public String getProperty(String key)
{
if (parent != null)
{
return parent.getProperty(name + "." + key);
}
return properties.getProperty(key);
}
/**
* Functions similarly to {@code getProperty(key, defaultValue)} but
* with the difference that if a property with the specified key does
* not exists, then the property will be set to the {@code defaultValue}
* argument and subsequently returned.
* @param key the property key
* @param defaultValue a default value
* @return the value in this property context with the specified key value.
*/
public String initProperty(String key, String defaultValue)
{
String value = getProperty(key);
if (value != null)
{
return value;
}
setProperty(key, defaultValue);
return defaultValue;
}
/**
* Searches for the property with the specified key in this property context.
* The method returns the default value argument if the property is not found.
*
* @param key the property key.
* @param defaultValue a default value.
* @return the value in this property context with the specified key value.
*/
public String getProperty(String key, String defaultValue)
{
if (parent != null)
{
return parent.getProperty(name + "." + key, defaultValue);
}
return properties.getProperty(key, defaultValue);
}
public Object setProperty(String key, String value)
{
if (value == null)
{
return removeProperty(key);
}
Object oldValue;
if (parent != null)
{
oldValue = parent.setProperty(name + "." + key, value);
}
else
{
oldValue = properties.setProperty(key, value);
}
support.firePropertyChange(key, oldValue, value);
return oldValue;
}
Object removeProperty(String key)
{
Object oldValue;
if (parent != null)
{
oldValue = parent.removeProperty(name + "." + key);
}
else
{
oldValue = properties.remove(key);
}
support.firePropertyChange(key, oldValue, null);
return oldValue;
}
String[] getStringArray(String key)
{
String prop = getProperty(key);
if (prop == null)
{
return null;
}
return StringUtils.split(prop, ';');
}
String[] getStringArray(String key, String[] defaultValue)
{
String prop = getProperty(key);
if (prop == null)
{
return defaultValue;
}
return StringUtils.split(prop, ';');
}
/**
* Sets property to the specified key to an array of Strings
* Note: This converts the string array into a single string
* by joining them using ';' as a separator
* @param key
* @param value
*/
private void setStringArray(String key, String[] value)
{
setProperty(key, StringUtils.join(value, ';'));
}
/**
* Note: this is mearly shorthand for: <br>
* {@code setStringArray(key, value.toArray(ArrayUtils.EMPTY_STRING_ARRAY))}
* @param key the property key
* @param value a list of strings
*/
void setStringArray(String key, List<String> value)
{
setStringArray(key, value.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
}
public int getInt(String key)
{
return NumberUtils.toInt(getProperty(key));
}
public int getInt(String key, int defaultValue)
{
return NumberUtils.toInt(getProperty(key, Integer.toString(defaultValue)));
}
public void setInt(String key, int integer)
{
setProperty(key, Integer.toString(integer));
}
public int initInt(String key, int defaultValue)
{
return NumberUtils.toInt(initProperty(key, Integer.toString(defaultValue)));
}
public boolean getBoolean(String key)
{
return Boolean.valueOf(getProperty(key));
}
public boolean getBoolean(String key, boolean defaultValue)
{
return Boolean.valueOf(getProperty(key, Boolean.toString(defaultValue)));
}
public void setBoolean(String key, boolean bool)
{
setProperty(key, Boolean.toString(bool));
}
public boolean initBoolean(String key, boolean defaultValue)
{
return Boolean.valueOf(initProperty(key, Boolean.toString(defaultValue)));
}
@Override
public void propertyChange(PropertyChangeEvent evt)
{
support.firePropertyChange(evt);
}
/**
* Called after properties have been loaded to allow any required
* post-load processing to be performed.
*/
protected void afterPropertiesLoaded()
{
}
/**
* Called before properties are saved to allow any required
* pre-save processing to be performed.
*/
protected void beforePropertiesSaved()
{
}
}