/*
* Configuration.java
*
* Created on 19. November 2002, 22:27
*/
package org.jconfig;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Set;
import java.util.SortedMap;
import javax.swing.event.EventListenerList;
import org.jconfig.event.ConfigurationChangedEvent;
import org.jconfig.event.ConfigurationChangedEventImpl;
/**
* This class is the configuration itself. The Configuration is
* useful if one wants to manage multiple configurations. A single
* instance of the Configuration may contain, for example, information
* for one application or user.
*
* @author Andreas Mecky andreas.mecky@xcom.de
* @author Terry Dye terry.dye@xcom.de
*/
public class NestedConfiguration extends DefaultConfiguration implements Serializable, Configuration {
private static final VariableManager vm = VariableManager.getInstance();
// The List of ConfigurationListeners
private EventListenerList configurationListenerList = new EventListenerList();
/**
* The constructor that creates a new configuration
* with one empty category called "general". This
* category is also the default category.
*
* @param configName the name of the configuration
*/
public NestedConfiguration(String configName) {
super(configName);
// System.err.println("new NestedConfiguraton "+ configName);
}
public String[] getCategoryNames() {
Set allCategories = categories.keySet();
Vector all = new Vector();
Iterator it = allCategories.iterator();
while ( it.hasNext() ) {
String name = (String)it.next();
addCategoryName(all,name);
}
if ( baseConfigName != null ) {
Configuration cfg = ConfigurationManager.getConfiguration(baseConfigName);
String[] parentCategories = cfg.getCategoryNames();
for ( int i = 0 ; i < parentCategories.length ; i++) {
if ( all.indexOf(parentCategories[i]) == -1 ) {
all.add(parentCategories[i]);
}
}
}
return (String[]) all.toArray(new String[0]);
}
private void addCategoryName(Vector all,String name) {
all.add(name);
NestedCategory myCat = (NestedCategory)getCategory(name);
Collection children = myCat.getChildCategories();
if ( children.size() > 0 ) {
Iterator it = children.iterator();
while ( it.hasNext() ) {
NestedCategory nc = (NestedCategory)it.next();
String cp = name + "/"+ nc.getCategoryName();
addCategoryName(all,cp);
}
}
}
protected String[] getCategoryNames(boolean includeParent) {
Set allCategories = categories.keySet();
Vector all = new Vector(allCategories);
if ( baseConfigName != null && includeParent ) {
Configuration cfg = ConfigurationManager.getConfiguration(baseConfigName);
String[] parentCategories = cfg.getCategoryNames();
for ( int i = 0 ; i < parentCategories.length ; i++) {
if ( all.indexOf(parentCategories[i]) == -1 ) {
all.add(parentCategories[i]);
}
}
}
return (String[]) all.toArray(new String[0]);
}
/**
* Besides setting the category, it will also set this
* category as default category if main is true. It will
* only set (ie create) the category if it does not exist. If you
* want delete a category then use @see #removeCategory(String)
*
* @param name the name of the category
* @param main if true then this category is the default category
*/
public void setCategory(String name, boolean main) {
if (name != null) {
if (main) {
mainCategory = name;
}
if (!categories.containsKey(name)) {
Category category = new NestedCategory(name);
category.setConfigurationName(configName);
category.addCategoryListener(new MyCategoryListener());
categories.put(name, category);
markDirty();
category.fireCategoryChangedEvent(
new ConfigurationChangedEventImpl(ConfigurationChangedEvent.CATEGORY_ADDED, category, null, null, null ));
}
}
}
public void setCategory(Category category) {
//if (!categories.containsKey(category.getCategoryName())) {
// System.err.println("NestedConfiguration.setCategory="+category);
category.setConfigurationName(configName);
category.addCategoryListener(new MyCategoryListener());
categories.put(category.getCategoryName(), category);
markDirty();
category.fireCategoryChangedEvent(
new ConfigurationChangedEventImpl(ConfigurationChangedEvent.CATEGORY_ADDED, category, null, null, null ));
//}
}
/**
* This is the real implementation. It will return the value of the property
* with the specific name. First of all, it checks if the name of the category
* exists. If not, then it will use the name of the default category.
* The next step is that it will look for the property. If it is not found in
* the category, it will look inside the default category (inheritance). If
* it still cannot find the property, it will return the defaultValue
*
* @param key the name of the property
* @param defaultValue the default value
* @param categoryName the name of the category
* @return the value as String
*/
public String getProperty(String key,String defaultValue,String categoryName) {
boolean isMainCat = false;
if (key == null) {
return defaultValue;
}
if ( categoryName == null ) {
isMainCat = true;
categoryName = mainCategory;
}
else if ( categoryName.indexOf("/") == -1 ) {
if (!categories.containsKey(categoryName)) {
isMainCat = true;
categoryName = mainCategory;
}
}
String tmp = null;
Category category = getCategory(categoryName);
if ( category != null ) {
if ( category.getCategoryName().equals(mainCategory)) {
isMainCat = true;
}
tmp = category.getProperty(key);
}
// property not found so look in mainCategory
// if it is not already the mainCategory
if ( tmp == null && !isMainCat) {
category = getCategory(mainCategory);
tmp = category.getProperty(key);
}
// maybe this config extends another one
if ( tmp == null ) {
if ( baseConfigName != null ) {
Configuration cfg = ConfigurationManager.getConfiguration(baseConfigName);
tmp = cfg.getProperty(key,defaultValue,categoryName);
}
else {
tmp = defaultValue;
}
}
return tmp;
}
/**
* This method creates a string representation of the configuration.
*
* @return a string with the configuration
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
String[] cats = getCategoryNames();
for (int i = 0; i < cats.length; i++) {
buffer.append("Category=");
buffer.append(cats[i]);
String[] propNames = getPropertyNames(cats[i]);
if (propNames != null) {
buffer.append("\n");
for (int j = 0; j < propNames.length; j++) {
buffer.append(" ");
buffer.append(propNames[j]);
buffer.append("=");
//buffer.append(replaceVariables(value));
buffer.append("\n");
}
}
}
return buffer.toString();
}
/**
* This method converts the Configuration into a String
* which looks like XML.
*
* @return the Configuration as String in XML format
*/
public String getXMLAsString() {
StringBuffer buffer = new StringBuffer();
// first we will write out the variable block
// if we have some
buffer.append("<?xml version=\"1.0\"");
if ( getEncoding() != null ) {
buffer.append(" encoding=\""+getEncoding()+"\"");
}
buffer.append(" ?>\n");
buffer.append("<properties");
if ( baseConfigName != null ) {
buffer.append(" extends=\"");
buffer.append(baseConfigName);
buffer.append("\"");
}
buffer.append(">\n");
addIncludeBlock(buffer);
addVariableBlock(buffer);
// this is only the list of top level categories
String[] cats = getCategoryNames(false);
for (int i = 0; i < cats.length; i++) {
NestedCategory nc = (NestedCategory)getCategory(cats[i]);
generateCategoryString(buffer, nc,nc.getCategoryName(),0);
}
buffer.append("</properties>\n");
return buffer.toString();
}
private void generateCategoryString(StringBuffer buffer,NestedCategory category,String categoryPath,int indent) {
indent +=2;
for ( int i = 0; i < indent;i++) {
buffer.append(" ");
}
buffer.append("<category name=\"");
buffer.append(escapeForXML(category.getCategoryName()));
buffer.append("\">\n");
SortedMap sm = getSortedProperties(categoryPath,false);
if (sm != null) {
Iterator nit = sm.keySet().iterator();
while (nit.hasNext()) {
String name = (String) nit.next();
String value = (String)sm.get(name);
for ( int i = 0; i < indent+2;i++) {
buffer.append(" ");
}
buffer.append("<");
buffer.append(escapeForXML(name));
buffer.append(">");
// do not convert the value
buffer.append(escapeForXML(value));
buffer.append("</");
buffer.append(escapeForXML(name));
buffer.append(">\n");
}
Collection children = category.getChildCategories();
if ( children.size() > 0 ) {
Iterator it = children.iterator();
while ( it.hasNext() ) {
NestedCategory nc = (NestedCategory)it.next();
String cp = categoryPath + "/"+ nc.getCategoryName();
generateCategoryString(buffer, nc,cp,indent);
}
}
for ( int i = 0; i < indent;i++) {
buffer.append(" ");
}
buffer.append("</category>\n");
indent -=2;
}
}
/**
* Returns a category based on the name provided.
* @param name The name of the category (if null, main category will be used)
* @return The category object (new instance if necessary)
*/
public Category getCategory(String name) {
return getCategory(name,true);
}
private Category getCategory(String name,boolean create) {
if(name == null) {
name = mainCategory;
}
NestedCategory category = null;
if ( name.indexOf("/") != -1 ) {
boolean first = true;
StringTokenizer sto = new StringTokenizer(name,"/");
while ( sto.hasMoreElements() ) {
String current = (String)sto.nextElement();
if ( first ) {
category = (NestedCategory)categories.get(current);
first = false;
}
else {
if ( category != null ) {
category = category.getCategory(current);
}
}
}
}
else {
category = (NestedCategory)categories.get(name);
if( category == null && create ) {
category = new NestedCategory(name);
categories.put(name, category);
}
}
if ( category == null && create ) {
category = createCategory(name);
}
return category;
}
private NestedCategory createCategory(String name) {
StringTokenizer sto = new StringTokenizer(name,"/");
String dir = null;
boolean first = true;
NestedCategory category = null;
NestedCategory parent = null;
while ( sto.hasMoreElements() ) {
String current = (String)sto.nextElement();
if ( first ) {
category = (NestedCategory)categories.get(current);
if ( category == null ) {
setCategory(current);
category = (NestedCategory)categories.get(current);
}
parent = category;
first = false;
}
else {
if ( category != null ) {
category = category.getCategory(current);
if ( category == null ) {
NestedCategory newCategory = new NestedCategory(current);
parent.addCategory(newCategory);
category = newCategory;
}
}
parent = category;
}
}
return category;
}
public boolean containsCategory(String categoryName) {
Category cat = getCategory(categoryName,false);
if ( cat == null ) {
return false;
}
else {
return true;
}
}
}